python小技巧 -- partial偏函数的应用

partial偏函数

partial的主要作用是将函数的部分参数固定,设置默认值。

举例说明:

1
2
3
4
5
6
7
8
9
10
11
import functools

def add(a, b, c, d):
    print(a + b + c + d)

adda = functools.partial(add, 1)

addb = functools.partial(adda, 1)

addc = functools.partial(addb, 1)

可以针对已经使用的偏函数仍可以继续使用

偏函数功能解析

偏函数固定参数的功能主要在 new 方法实现

详细解析在注释中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def __new__(*args, **keywords):

    # 参数判断
    if not args:
        raise TypeError("descriptor '__new__' of partial needs an argument")
    if len(args) < 2:
        raise TypeError("type 'partial' takes at least one argument")
    cls, func, *args = args
    if not callable(func):
        raise TypeError("the first argument must be callable")
    args = tuple(args)

    # 为已经是偏函数的函数继续使用设置
    if hasattr(func, "func"):
        args = func.args + args
        tmpkw = func.keywords.copy()
        tmpkw.update(keywords)
        keywords = tmpkw
        del tmpkw
        func = func.func
    
    # 创建新对象
    self = super(partial, cls).__new__(cls)

    # 为新对象增加方法
    self.func = func
    self.args = args
    self.keywords = keywords
    return self

至此参数固定已经完成

在调用时会调用 call 方法

1
2
3
4
5
6
7
def __call__(*args, **keywords):
    if not args:
        raise TypeError("descriptor '__call__' of partial needs an argument")
    self, *args = args
    newkeywords = self.keywords.copy()
    newkeywords.update(keywords)
    return self.func(*self.args, *args, **newkeywords)

此方法就比较简单,直接调用执行

实际应用场景

除了再参数较多时应用,在qt开发时也遇到类型场景:

qt绑定按钮事件时,如果按钮事件有参数时不能直接设置(直接设置时会直接运行)

此时可以使用偏函数解决

1
2
3
4
5
6
7

callsave_pdf = functools.partial(self.save_pdf, is_tips=True)
self.pushButton_save.clicked.connect(callsave_pdf)

# 或者使用lambda
self.pushButton_save.clicked.connect(lambda: self.save_pdf(is_tips=True))

“世界就像是个巨大的马戏团,它让你兴奋,却让我惶恐,因为我知道散场后永远是有限温存,无限心酸。”