functool.partialmethod和functool.partial的用法?

gol*_*ode 4 python methods partial python-3.x

考虑以下代码:

import functools
import inspect

class Foo:
    def foo_fn(self, hello, world):
        print(hello, world)

class FooWrapper:
    def __init__(self, foo_class):
        self._foo = foo_class()
        for key, value in inspect.getmembers(self._foo):
            if inspect.ismethod(value):
                bound_fn = functools.partial(self.foo_wrapper_fn, self, value)
                setattr(self._foo, key, bound_fn)

    def foo_wrapper_fn(self_wrapper, self_foo, bound_method, hello, world):
        bound_method(hello, world)

def make_foo(Foo):
    wrapper = FooWrapper(Foo)
    return wrapper._foo
a = make_foo(Foo)
a.foo_fn("hello", "world")
Run Code Online (Sandbox Code Playgroud)
  1. foo_wrapper_fn()像这样的功能参数如何排序(self_wrapper, self_foo, bound_method, hello, world)?而不是这样:self_wrapper, bound_fn, self_foo, hello, world,由于self_wrapperbound_fn首先被部分绑定?

  2. 对象()调用返回functool.partial (而不是functool.partialmethod可以a.foo_fn吗?

  3. 如果我将其替换为functools.partialmethod(self.foo_wrapper_fn, self, value) 为什么会出现此错误?

    TypeError: 'partialmethod' object is not callable
    
    Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 5

这两个第一个参数是同一个对象self.foo_wrapper_fn绑定到FooWrapper实例(就像在实例上一样self),然后您告诉分部self 再次传入。因此,实际上,签名只是一个双重困惑,您可以省略第二个参数,而不必传入第二个显式变量self

请注意,您永远不会经过self._foo任何地方。

该顺序只需通过以下方式设置:

  1. 绑定方法,传入绑定FooWrapper()实例。
  2. 无论您传递给partial()调用的是什么位置参数,都这样 self, value。那FooWrapper()实例,以及绑定方法。Foo
  3. 调用partial()对象时传递的任何其他参数。

必须partial()此处使用一个对象,而不是一个partialmethod(),因为您要在实例上设置属性。A partialmethod()旨在用作描述符对象,例如,类上的属性。

这就是为什么你也得到你的东西TypeError。在partialmethod()从来没有约束。如果已绑定(调用了它的__get__方法,并传入要绑定的实例),则将返回正确的可调用对象。

有关描述符如何工作的信息,请参见Python 描述符方法。(绑定方法是通过该协议创建的,而partialmethod对象以及propertyclassmethodstaticmethod对象均基于相同的原理构建)。

因此,您可以使用以下代码简化代码:

class FooWrapper:
    def __init__(self, foo_class):
        self._foo = foo_class()
        for key, value in inspect.getmembers(self._foo):
            if inspect.ismethod(value):
                bound_fn = functools.partial(self.foo_wrapper_fn, value)
                setattr(self._foo, key, bound_fn)

    def foo_wrapper_fn(self, bound_method, hello, world):
        bound_method(hello, world)
Run Code Online (Sandbox Code Playgroud)

如果必须访问原始Foo()实例,请使用变量__self__上的属性bound_method