python - 装饰方法

标签 python methods decorator

在我的 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参数。

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

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 时被调用,并且将传递一个未绑定(bind) 方法,而不是实例的绑定(bind)方法。这就是 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 调用 f.some_method 时被调用...但整点你的计划是没有人这样做!事件回调机制直接调用 listen 实例,因为这是它传递的内容,listen 实例正在调用它在创建时隐藏起来的未绑定(bind)方法。 listen.__get__ 永远不会被调用并且 _self 参数永远不会正确设置...除非您显式访问 self .some_method 自己,就像我在上面的 __init__ 方法中所做的那样。然后 listen.__get__ 将在实例创建时调用,并且 _self 将被正确设置。

问题是 (a) 这是一个可怕的骇人听闻的 hack 和 (b) 如果您尝试创建 Foo 的两个实例,那么第二个实例将覆盖 _self由第一个设置,因为仍然只有一个 listen 对象被创建,并且它与类关联,而不是实例。如果你只使用一个 Foo 实例那么你很好,但是如果你必须让事件触发两个不同的 Foo 那么你只需要使用您的“旧式”事件注册。

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

关于python - 装饰方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3401421/

相关文章:

python - 为什么这个 Pythonlogging.exception 不起作用?

delphi - 定义方法的问题

java - Kotlin 中接口(interface)的 Lambda 实现

python - 如何区分装饰器中的方法和函数?

python - 如何为CommandCollection点击的命令添加帮助?

python - 使用 python 将列表元素转换为连续的元组

typescript - Typescript 中装饰器的别名

django登录后返回上一页

python - python中的安全凭证存储

Java - 方法中的变量在调用后未被删除