【问题标题】:Setting a functools.partial as an instance method in Python在 Python 中将 functools.partial 设置为实例方法
【发布时间】:2015-07-16 23:06:25
【问题描述】:

我使用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 的第一个参数,这将释放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)

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

【问题讨论】:

  • @alfasin 该问题询问有关向特定实例添加方法的问题;我的问题是关于向类中添加方法,以供所有实例继承
  • 是的,但接受的答案显示了如何做到这两点

标签: python class methods closures


【解决方案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

【讨论】:

    【解决方案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()
    

    【讨论】:

    • 这行得通!我想没有办法立即将闭包添加为MethodType,而不是在调用时即时转换它?
    猜你喜欢
    • 1970-01-01
    • 2012-06-07
    • 2018-06-14
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 2013-05-13
    相关资源
    最近更新 更多