functool.partialmethod 和 functool.partial 的用法?

Usage of functool.partialmethod and functool.partial?

考虑以下代码:

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")
  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 的 return (而不是 functool.partialmethod 可以被调用吗对象 (a.foo_fn)?

  3. 如果我用functools.partialmethod(self.foo_wrapper_fn, self, value)替换它为什么会出现这个错误?

    TypeError: 'partialmethod' object is not callable
    

两个第一个参数是同一个对象self.foo_wrapper_fn 绑定到 FooWrapper 实例(因为它是在 self 上查找的),然后您告诉部分对象再次传入 self 。所以实际上,签名只是一个双重混淆,你可以省略第二个参数,而不是直接传递第二个,显式 self.

请注意,您永远不会在任何地方传递 self._foo

顺序简单地设置为:

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

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

上的属性

这就是为什么您也得到 TypeError 的原因; partialmethod() 从未被绑定。如果它被绑定(它的 __get__ method 被调用,传入要绑定的实例),那么将返回一个适当的可调用对象。

参见 Python Descriptor Howto 了解描述符的工作原理(绑定方法是通过该协议创建的,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)

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