【问题标题】:Using pydispatch and decorators for class methods对类方法使用 pydispatch 和装饰器
【发布时间】:2015-08-22 01:38:10
【问题描述】:

我正在尝试一些相当简单的事情。我想编写一个装饰器,它使用 pydispatcher 在事件处理程序中转换类方法。这是我的基本方法:

from pydispatch.dispatcher import connect,send,Any

SIGNAL = "test"

def triggered(func):
    connect(func,signal=SIGNAL,sender = Any)
    return func

class P(object):
    @triggered
    def a(self,*args,**kwargs):
        print "yay"

if __name__ == "__main__":
    p = P()
    send(signal=SIGNAL,sender="")

这会引发错误:

Traceback (most recent call last):
  File "util.py", line 35, in <module>
    send(signal=SIGNAL,sender="")
  File "/usr/local/lib/python2.7/dist-packages/pydispatch/dispatcher.py", line 338, in send
    **named
  File "/usr/local/lib/python2.7/dist-packages/pydispatch/robustapply.py", line 55, in robustApply
    return receiver(*arguments, **named)
TypeError: a() takes at least 1 argument (0 given)

有什么想法吗?

【问题讨论】:

    标签: python decorator class-method


    【解决方案1】:

    您在一个类中注册了一个函数。这意味着只是注册了函数,而不是绑定的方法。函数未绑定到实例,因此没有传入 self 参数。

    您不能希望在类定义中的常规方法上使用装饰器,因为当时所需的上下文(实例)不可用。

    您必须先创建一个实例,然后注册绑定到该实例的方法才能使其工作:

    class P(object):
        def a(self, *args, **kwargs):
            print "yay"
    
    if __name__ == "__main__":
        p = P()
        triggered(p.a)
        send(signal=SIGNAL,sender="")
    

    现在triggered()注册p.a绑定方法;调用该方法将在调用时将p 作为self 参数传入。

    您也可以将a 方法设为staticclass 方法。静态方法本质上只是一个函数;它从不接受self 参数。这意味着您可以将其注册为信号处理程序,但您永远不会获得使用类的好处:

    class P(object):
        @staticmethod
        @triggered
        def a(*args, **kwargs):
            print "yay"
    

    如果您将其设为类方法,您将获得传入的类(仍然不是实例),并且您将必须在类外进行注册以确保获得绑定方法:

    class P(object):
        @classmethod
        def a(cls, *args, **kwargs):
            print "yay"
    
    triggered(P.a)
    

    【讨论】:

    • 所以问题的核心是每个事件系统都必须处理实例,而装饰器添加静态功能。我是否正确看待这一点?
    • @Kai:装饰器在创建函数时对其进行操作;类主体中的函数是在创建类之前创建的。因此,您的装饰器只注册函数,而不是方法(通过将函数引用为类或实例的属性来创建)。如果你想处理一个绑定方法,你需要先创建一个实例。这实际上取决于您希望在事件触发时拥有什么作为上下文。
    • 感谢您的澄清!不幸的是,这使我的第一个想法无法实现,从好的方面来说,我学到了很多关于装饰器的知识。感谢分享!
    猜你喜欢
    • 2014-01-14
    • 2020-01-11
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 2019-02-03
    相关资源
    最近更新 更多