Python:为什么functools.partial函数在设置为类属性时不会成为绑定方法



我读到函数在设置为类atrributes时如何成为绑定方法。然后我观察到,对于由functools.partial封装的函数,情况并非如此。对此有何解释?

简单示例:

from functools import partial
def func1():
print("foo")
func1_partial = partial(func1)
class A:
f = func1
g = func1_partial
a = A()

a.f() # TypeError: func1() takes 0 positional arguments but 1 was given
a.g() # prints "foo"

我有点期待他们两个都有同样的行为。

允许函数成为绑定方法的诀窍是__get__魔术方法。

为了简单地总结该页面,当您访问实例上的字段(例如foo.bar(时,Python首先检查bar是否存在于foo__dict__中(或者__slots__,如果有(。如果真的发生了,我们就归还它,不会造成任何伤害。如果不是,那么我们看type(foo)然而,当我们通过实例访问Foo上的字段Foo.bar时,神奇的事情发生了。当我们写foo.bar时,假设foo__dict__(分别为__slots__(上没有bar,那么我们实际上调用Foo.bar.__get__(foo, Foo)。也就是说,Python调用一个神奇的方法,询问对象希望如何检索。

这就是属性的实现方式,也是绑定方法的实现方式。在某种深处(可能是用C编写的(,类型function上有一个__get__函数,它在通过实例访问时绑定该方法。

尽管functools.partial看起来很像一个函数,但它不是function类型的实例。它只是一个碰巧实现__call__的随机类,而它没有实现__get__。为什么不呢?嗯,他们可能只是觉得这不值得,或者可能没有人考虑过;绑定方法";技巧适用于名为function的类型,而不是所有可调用对象。


关于魔术方法的另一个有用资源,尤其是__get__:https://rszalski.github.io/magicmethods/#descriptor

类型function实现__get__方法:

>>> import types
>>> types.FunctionType.__get__
<slot wrapper '__get__' of 'function' objects>

partial没有。

>>> from functools import partial
>>> partial.__get__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'functools.partial' has no attribute '__get__'. Did you mean: '__ge__'?

__get__方法使a.f评估为method类型的值,而不是A.f类型的值。如果没有__get__,则a.g等效于A.g

最新更新