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")
函数 foo_wrapper_fn()
参数如 (self_wrapper, self_foo, bound_method, hello, world)
的这种排序是如何形成的?
而不是这样:self_wrapper, bound_fn, self_foo, hello, world
,因为 self_wrapper
和 bound_fn
首先被部分绑定?
functool.partial
的 return (而不是 functool.partialmethod
) 可以被调用吗对象 (a.foo_fn
)?
如果我用functools.partialmethod(self.foo_wrapper_fn, self, value)
替换它为什么会出现这个错误?
TypeError: 'partialmethod' object is not callable
两个第一个参数是同一个对象。 self.foo_wrapper_fn
绑定到 FooWrapper
实例(因为它是在 self
上查找的),然后您告诉部分对象再次传入 self
。所以实际上,签名只是一个双重混淆,你可以省略第二个参数,而不是直接传递第二个,显式 self
.
请注意,您永远不会在任何地方传递 self._foo
。
顺序简单地设置为:
- 绑定方法,传入绑定的
FooWrapper()
实例。
- 无论您传递给
partial()
调用的位置参数是什么,所以
self, value
。那是 FooWrapper()
实例 再次 和绑定 Foo
方法。
- 您在调用
partial()
对象时传入的任何其他参数。
您必须在此处使用partial()
对象,而不是partialmethod()
,因为您是在实例上设置属性。 partialmethod()
旨在用作描述符对象,例如class.
上的属性
这就是为什么您也得到 TypeError
的原因; partialmethod()
从未被绑定。如果它被绑定(它的 __get__
method 被调用,传入要绑定的实例),那么将返回一个适当的可调用对象。
参见 Python Descriptor Howto 了解描述符的工作原理(绑定方法是通过该协议创建的,partialmethod
对象,以及 property
、classmethod
和 staticmethod
对象,都建立在相同的原则上)。
因此您可以通过以下方式简化代码:
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__
属性。
考虑以下代码:
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")
函数
foo_wrapper_fn()
参数如(self_wrapper, self_foo, bound_method, hello, world)
的这种排序是如何形成的? 而不是这样:self_wrapper, bound_fn, self_foo, hello, world
,因为self_wrapper
和bound_fn
首先被部分绑定?functool.partial
的 return (而不是functool.partialmethod
) 可以被调用吗对象 (a.foo_fn
)?如果我用
functools.partialmethod(self.foo_wrapper_fn, self, value)
替换它为什么会出现这个错误?TypeError: 'partialmethod' object is not callable
两个第一个参数是同一个对象。 self.foo_wrapper_fn
绑定到 FooWrapper
实例(因为它是在 self
上查找的),然后您告诉部分对象再次传入 self
。所以实际上,签名只是一个双重混淆,你可以省略第二个参数,而不是直接传递第二个,显式 self
.
请注意,您永远不会在任何地方传递 self._foo
。
顺序简单地设置为:
- 绑定方法,传入绑定的
FooWrapper()
实例。 - 无论您传递给
partial()
调用的位置参数是什么,所以self, value
。那是FooWrapper()
实例 再次 和绑定Foo
方法。 - 您在调用
partial()
对象时传入的任何其他参数。
您必须在此处使用partial()
对象,而不是partialmethod()
,因为您是在实例上设置属性。 partialmethod()
旨在用作描述符对象,例如class.
这就是为什么您也得到 TypeError
的原因; partialmethod()
从未被绑定。如果它被绑定(它的 __get__
method 被调用,传入要绑定的实例),那么将返回一个适当的可调用对象。
参见 Python Descriptor Howto 了解描述符的工作原理(绑定方法是通过该协议创建的,partialmethod
对象,以及 property
、classmethod
和 staticmethod
对象,都建立在相同的原则上)。
因此您可以通过以下方式简化代码:
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__
属性。