装饰方法
在我的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__
,也不知道如何合并参数。仅出于测试目的,我尝试使用固定事件进行侦听,但是使用这种方法,什么也没有发生。当我添加打印语句时,可以看到__init__
被调用。如果我添加一个额外的“旧式”活动报名,都__get__
和__call__
得到执行,而该事件的作品,尽管新的装饰。
什么是实现我想要的最佳方法,或者我只是缺少装饰器的一些重要概念?
-
装饰器方法不起作用,因为装饰器是在构造类时调用的,而不是在构造实例时调用的。当你说
class Foo(object): @some_decorator def bar(self, *args, **kwargs): # etc etc
然后
some_decorator
在构造类Foo时将调用它,并将为它传递一个 未绑定 方法,而不是实例的绑定方法。这就是为什么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版本:装饰方法装饰类的 未绑定 方法,而您希望事件管理器传递实例的 绑定 方法。