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

fou*_*ver 8 python class python-3.x functools

我正在阅读有关函数在设置为类 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"

Run Code Online (Sandbox Code Playgroud)

我有点期望他们都会有同样的行为方式。

Sil*_*olo 7

允许函数成为绑定方法的技巧就是__get__魔术方法

非常简单地总结一下该页面,当您访问实例上的字段(例如 )时,foo.barPython 首先检查'sbar中是否存在(或者,如果有的话)。如果确实如此,我们会将其退回,不会造成任何伤害。如果没有,那我们就拭目以待吧。然而,当我们通过实例访问上的字段时,神奇的事情发生了。当我们写 时,假设没有on的(resp. ),那么我们实际上调用foo__dict____slots__type(foo)Foo.bar Foofoo.barbarfoo__dict____slots__Foo.bar.__get__(foo, Foo). 也就是说,Python 调用一个魔术方法来询问对象希望如何检索它。

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

functools.partial尽管看起来很像函数,但它并不是类型 的实例function。它只是一个随机的类,碰巧实现了__call__,并且没有实现__get__。为什么不呢?好吧,他们可能只是认为这不值得,或者可能根本没有人考虑过。无论如何,“绑定方法”技巧适用于调用的类型function,而不是所有可调用对象。


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

  • 请注意,“Foo.bar”也很“神奇”。`__get__` 方法仍然被调用,但它只是返回函数本身,而不是 `method` 的新实例。 (2认同)

che*_*ner 5

该类型function实现了该__get__方法:

>>> import types
>>> types.FunctionType.__get__
<slot wrapper '__get__' of 'function' objects>
Run Code Online (Sandbox Code Playgroud)

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__'?
Run Code Online (Sandbox Code Playgroud)

__get__方法使a.f评估结果为 type 的值method而不是A.f. 没有__get__a.g相当于A.g