将functools.partial设置为Python中的实例方法

时间:2015-07-16 23:06:26

标签: python class methods closures

我正在使用functools.partial来创建一个闭包,并且使用setattr来创建可以从类实例中调用。这里的想法是在运行时创建一组方法。

#!/usr/bin/python
from functools import partial

class MyClass(object):

    def __init__(self, val):
        self.val = val

    @classmethod
    def generateMethods(self):
        def dummy(conf1, self):
            print "conf1:", conf1
            print "self.val:", self.val
            print

        for s in ('dynamic_1', 'dynamic_2'):
            closed = partial(dummy, s)
            setattr(self, "test_{0}".format(s), closed)

在我看来,partial会将s的当前值绑定到dummy的第一个arg,当这是self时,会释放if __name__ == '__main__': # Dynamically create some methods MyClass.generateMethods() # Create an instance x = MyClass('FOO') # The dynamically created methods aren't callable from the instance :( #x.test_dynamic_1() # TypeError: dummy() takes exactly 2 arguments (1 given) # .. but these work just fine MyClass.test_dynamic_1(x) MyClass.test_dynamic_2(x) 从一个实例调用。

这不符合我的预期

{{1}}

是否可以动态创建闭包方法,但可以从类的实例中调用?

2 个答案:

答案 0 :(得分:2)

问题在于,当您使用实例调用它们时,它们实际上不是绑定方法,即它们不了解实例。绑定方法在调用时自动将self插入到底层函数的参数中,它存储在绑定方法的__self__属性中。

因此,覆盖__getattribute__并查看正在提取的对象是否是partial类型的实例,如果是,则使用types.MethodType将其转换为绑定方法。

<强>代码:

#!/usr/bin/python
from functools import partial
import types


class MyClass(object):

    def __init__(self, val):
        self.val = val

    @classmethod
    def generateMethods(self):
        def dummy(conf1, self): 
            print "conf1:", conf1
            print "self.val:", self.val
            print

        for s in ('dynamic_1', 'dynamic_2'):
            closed = partial(dummy, s)
            setattr(self, "test_{0}".format(s), closed)

    def __getattribute__(self, attr):
        # Here we do have access to the much need instance(self)
        obj = object.__getattribute__(self, attr)
        if isinstance(obj, partial):    
            return types.MethodType(obj, self, type(self))
        else:
            return obj


if __name__ == '__main__':
    MyClass.generateMethods()

    x = MyClass('FOO')

    x.test_dynamic_1()
    x.test_dynamic_2()

答案 1 :(得分:1)

我认为新的functools.partialmethod适用于这个确切的用例。

直接来自文档:

>>> class Cell(object):
...     def __init__(self):
...         self._alive = False
...     @property
...     def alive(self):
...         return self._alive
...     def set_state(self, state):
...         self._alive = bool(state)
...     set_alive = partialmethod(set_state, True)
...     set_dead = partialmethod(set_state, False)
...
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True