functool.partialmethod和functool.partial的用法?

时间:2016-12-09 23:17:26

标签: python python-3.x methods 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)是否可以返回functool.partialmethod (而不是a.foo_fn

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

    TypeError: 'partialmethod' object is not callable
    

1 个答案:

答案 0 :(得分:4)

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

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

订单只需按以下方式设定:

  1. 绑定方法,传入绑定的FooWrapper()实例。
  2. 无论你传递给partial()的所有位置参数,都是如此 self, value。那是FooWrapper()实例再次,以及绑定的Foo方法。
  3. 调用partial()对象时传入的任何其他参数。
  4. 在此处使用partial()对象,而不是partialmethod(),因为您要在实例上设置属性。 partialmethod()旨在用作描述符对象,例如,班上的一个属性。

    这就是你获得TypeError的原因; partialmethod()从未受到约束。如果它被绑定(它被调用__get__ method,传入实例以绑定到),那么就会返回一个正确的可调用对象。

    请参阅Python Descriptor Howto有关描述符的工作方式(通过该协议创建绑定方法,partialmethod个对象,以及propertyclassmethod和{{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__属性。