我读到函数在设置为类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
。