请考虑以下代码:
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
)是否可以返回functool.partialmethod
(而不是a.foo_fn
)?
如果我将其替换为functools.partialmethod(self.foo_wrapper_fn, self, value)
,为什么会出现此错误?
TypeError: 'partialmethod' object is not callable
答案 0 :(得分:4)
两个第一个参数都是相同的对象。 self.foo_wrapper_fn
绑定到FooWrapper
实例(因为它在self
上查找),然后您告诉部分再次传入self
。实际上,签名只是一个双重混淆,你可以省去第二个参数,而不是传递第二个,明确的self
。
请注意,您永远不会在任何地方传递self._foo
。
订单只需按以下方式设定:
FooWrapper()
实例。partial()
的所有位置参数,都是如此
self, value
。那是FooWrapper()
实例再次,以及绑定的Foo
方法。partial()
对象时传入的任何其他参数。您 在此处使用partial()
对象,而不是partialmethod()
,因为您要在实例上设置属性。 partialmethod()
旨在用作描述符对象,例如,班上的一个属性。
这就是你获得TypeError
的原因; partialmethod()
从未受到约束。如果它被绑定(它被调用__get__
method,传入实例以绑定到),那么就会返回一个正确的可调用对象。
请参阅Python Descriptor Howto有关描述符的工作方式(通过该协议创建绑定方法,partialmethod
个对象,以及property
,classmethod
和{{1}对象,都建立在相同的原则上。)
因此,您可以使用以下方法简化代码:
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()
变量上的__self__
属性。