Python 装饰一种方法

Python 装饰一种方法,python,methods,decorator,Python,Methods,Decorator,在我的Python应用程序中,我使用事件在不同插件之间进行通信。 现在,我不想手动将方法注册到事件中,我想我可以使用decorator来完成这项工作 我希望它看起来像这样: @events.listento('event.name') def myClassMethod(self, event): ... def listento(to): def listen_(func): myEventManager.listen(to, func) de

在我的Python应用程序中,我使用事件在不同插件之间进行通信。 现在,我不想手动将方法注册到事件中,我想我可以使用decorator来完成这项工作

我希望它看起来像这样:

@events.listento('event.name')
def myClassMethod(self, event):
    ...
def listento(to):
    def listen_(func):
        myEventManager.listen(to, func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return func
    return listen_
我首先尝试这样做:

@events.listento('event.name')
def myClassMethod(self, event):
    ...
def listento(to):
    def listen_(func):
        myEventManager.listen(to, func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return func
    return listen_
当我从实例中调用
myEventManger.listen('event',self.method)
时,一切都正常运行。但是,如果使用decorator方法,则永远不会传递
self
参数

在互联网上搜索解决方案后,我尝试的另一种方法是使用类作为装饰器:

class listen(object):
    def __init__(self, method):
        myEventManager.listen('frontend.route.register', self)
        self._method = method
        self._name = method.__name__
        self._self = None

    def __get__(self, instance, owner):
        self._self = instance
        return self

    def __call__(self, *args, **kwargs):
        return self._method(self._self, *args, **kwargs)
这种方法的问题是,我不太理解
\uuuu get\uuu
的概念,也不知道如何合并参数。 为了进行测试,我尝试使用固定的事件来监听,但是使用这种方法,什么也没发生。当我添加print语句时,我可以看到调用了
\uuuu init\uuuu
。 如果我添加一个额外的“旧式”事件注册,则执行
\uuuuuu get\uuuuuu
\uuuuu call\uuuuuuuuu
这两个事件,尽管使用了新的装饰器,但事件仍然有效


实现我想要的目标的最佳方法是什么,或者我只是缺少了装饰器的一些重要概念?

装饰器方法不起作用,因为装饰器是在构造类时调用的,而不是在构造实例时调用的。当你说

class Foo(object):
  @some_decorator
  def bar(self, *args, **kwargs):
    # etc etc
然后,在构造类Foo时,将调用某个_decorator,并将向它传递一个未绑定的方法,而不是实例的绑定方法。这就是为什么
self
没有通过考试的原因

另一方面,第二种方法可以工作,只要您对使用装饰器的每个类只创建一个对象,并且您稍微聪明一点。如果您定义
请按上述方法听
,然后定义

class Foo(object):
  def __init__(self, *args, **kwargs):
    self.some_method = self.some_method # SEE BELOW FOR EXPLANATION
    # etc etc
  @listen
  def some_method(self, *args, **kwargs):
    # etc etc
然后
听。当有人试图调用
f时,会调用\uu get\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!事件回调机制直接调用
listen
实例,因为这就是它传递的内容,而
listen
实例正在调用创建时存储的未绑定方法<代码>侦听。\uuuu get\uuuuuu
永远不会被调用,
\u self
参数永远不会正确设置……除非您显式访问
self。一些方法是您自己
的,就像我在上面的
\uuuu init\uuuuuuuu
方法中所做的那样。然后,
listen.\uuuu get\uuuu
将在创建实例时被调用,并且
\u self
将被正确设置

问题是(a)这是一个可怕的黑客行为,(b)如果您尝试创建两个
Foo
实例,那么第二个实例将覆盖第一个实例设置的
\u self
,因为仍然只有一个
listen
对象被创建,并且该对象与类关联,而不是与实例关联。如果您只使用一个
Foo
实例,那么您就可以了,但是如果您必须让事件触发两个不同的
Foo
,那么您只需要使用“旧式”事件注册

TL,DR版本:装饰方法装饰类的未绑定方法,而您希望事件管理器通过实例的绑定方法。

< P>代码的一部分是:

    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return func

它定义了
wrapper
,然后完全忽略它并返回
func
。很难说这在您的真实代码中是否是一个真正的问题,因为显然您没有发布这一问题(如
myEventManagre
myEvnetManager
,&c等打字错误证明了这一点),但是,如果这是您在实际代码中所做的,那么显然是您的问题的一部分。

您确定在定义了方法之后,只调用
myEventManager.listen('frontend.route.register',myClassMethod')
不会更高兴吗?由于您根本没有修改该方法的行为,我不确定decorator是否最适合这里。我希望直接从方法定义中看到哪个方法注册到哪个事件。我刚刚为事件注册发明了一些东西,所以很清楚这是什么意思:)抱歉,写得太草率,当时很早。。。无论如何,你是对的,这是一个我没有发现的实际错误(wrapper vs func)。但是,最后它没有什么区别,因为我根本不想改变方法,所以我可以完全省略包装器。啊,我想我现在明白了。非常感谢您的详细解释!所以没有什么,嗯,让我们称之为正确的方式,我在寻找什么?我不知道。如果您仅以
f的身份访问方法,您发现的“类作为具有
\uuu get\uuuu
的decorator”技巧会在某种程度上装饰一个方法。有些方法()
,但这种技术有局限性,您第一次尝试时恰好发现了其中一种。