在我的Python应用程序中,我正在使用事件在不同的插件之间进行通信。 现在,我没有手动将方法注册到事件,我想我可能会使用装饰器为我做这些。
我希望看起来像这样:
@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)
时,一切运行正常。但是,如果我使用装饰器方法,则永远不会传递self
参数。
在Internet上搜索解决方案之后,我尝试过的另一种方法是使用类作为装饰器:
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)
这种方法的问题在于我并不真正理解__get__
的概念,而且我不知道如何合并这些参数。
仅仅为了测试我尝试使用固定事件来收听,但采用这种方法,没有任何反应。当我添加print语句时,我可以看到__init__
被调用。
如果我添加了一个额外的“旧式”事件注册,__get__
和__call__
都会被执行,尽管有新的装饰器,但事件仍然有效。
实现我正在寻找的东西的最佳途径是什么,或者我只是缺少装饰师的一些重要概念?
答案 0 :(得分:4)
装饰器方法不起作用,因为在构造类时调用装饰器,而不是在构造实例时调用。当你说
class Foo(object):
@some_decorator
def bar(self, *args, **kwargs):
# etc etc
然后在构造类Foo时将调用some_decorator
,并且它将传递未绑定的方法,而不是实例的绑定方法。这就是为什么self
没有通过。
另一方面,第二种方法可以工作,只要你只创建使用装饰器的每个类的一个对象,和如果你'有点聪明。如果您按上述方式定义listen
,然后定义
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
当有人试图直接为某些listen.__get__
致电f.some_method
时,系统会调用f
...但您的方案的重点是没有人这样做!事件回调机制直接调用listen
实例'因为它传递的是什么,listen
实例正在调用它在创建时松开的未绑定方法。永远不会调用listen.__get__
并且_self
参数永远不会被正确设置... 除非您自己明确访问self.some_method
,就像我在上面的__init__
方法。然后在创建实例时调用listen.__get__
,并正确设置_self
。
问题是(a)这是一个可怕的,可怕的黑客和(b)如果你试图创建Foo
的两个实例,那么第二个将覆盖第一个_self
设置,因为仍然只创建了一个listen
对象,并且该对象与类相关联,而不是与实例相关联。如果你只使用一个Foo
实例,那么你很好,但是如果你必须让事件触发两个不同的Foo
,那么你只需要使用你的“旧式”事件注册
TL,DR版本:装饰方法会修饰类的未绑定方法,而您希望事件管理器传递实例的绑定方法。
答案 1 :(得分:3)
您的部分代码是:
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return func
定义wrapper
然后完全忽略它并返回func
。很难说这是否是真实代码中的真正问题,因为很明显你没有发布(正如myEventManagre
,myEvnetManager
和& c)这样的错字证明了这一点,但如果这就是你的话在您的实际代码中, 显然是您问题的一部分。