【问题标题】:Dynamically add a decorator to class动态添加装饰器到类
【发布时间】:2013-04-04 06:21:31
【问题描述】:

我有一个相当大且涉及的decorator to debug PyQt signals,我想动态添加到一个类中。有没有办法给类动态添加装饰器?

我可能从错误的角度来处理这个问题,所以这就是我想要完成的。

目标

  1. 我有一个装饰器,它会发现/附加到类中的所有 pyqt 信号,并在发出这些信号时打印调试。
  2. 这个装饰器非常适合调试单个类的信号。但是,有时我想将我的所有信号附加到应用程序中。这可用于查看我是否在意外时间发出信号等。
  3. 我想将此装饰器动态附加到我的所有具有信号的类。

可能的解决方案/想法

到目前为止,我已经考虑了一些可能的解决方案:

  1. 继承:如果我所有的类都具有相同的基类(除了 Python 的内置 object 和 PyQt 的内置 QtCore.QObject),这将很容易。我想我可以把这个装饰器附加到我的基类上,一切都会按预期进行。但是,在此特定应用程序中并非如此。我也不想将我的所有类都更改为具有相同的基类。
  2. Monkey-patch Python objectQtCore.QObject:我不知道这将如何实际工作。但是,理论上我可以将这些基类之一的__init__ 更改为我在装饰器中定义的new_init 吗?这看起来真的很危险和骇人听闻,但也许这是一个方法?
  3. 元类:我认为元类不会在这种情况下工作,因为我必须将__metaclass__ 属性动态添加到我想要将装饰器注入到的类中。我认为这是不可能的,因为要插入此属性,必须已经构造了该类。因此,我定义的任何元类都不会被调用。这是真的?

我尝试了一些元类魔法的变体,但似乎没有任何效果。我觉得使用元类可能是实现我想要的一种方式,但我似乎无法让它发挥作用。

再一次,我可能会搞错这一切。本质上,我想将上面引用的装饰器中的行为附加到我的应用程序中的所有类(甚至可能是选择类的列表)。此外,如有必要,我可以重构我的装饰器。我真的不在乎我是否将此行为与装饰器或其他机制相结合。我只是假设这个装饰器已经完成了我对单个类的要求,所以它可能很容易扩展。

【问题讨论】:

    标签: python pyqt pyqt4 decorator python-decorators


    【解决方案1】:

    装饰器只不过是自动应用的可调用对象。要手动应用它,请将类替换为装饰器的返回值:

    import somemodule
    
    somemodule.someclass = debug_signals(somemodule.someclass)
    

    这会将 somemodule.someclass 名称替换为 debug_signals 的返回值,我们传递了原始的 somemodule.someclass 类。

    【讨论】:

    • 这确实有效。但是,此解决方案仍然存在必须手动添加装饰器的相同问题。我想动态地将功能添加到所有类,而不必知道它们的名称等。对于这个解决方案,我必须导入类并手动添加装饰器。因此,与仅将@debug_signals 添加到类本身相比,这似乎没有任何好处。我错过了什么吗?
    • @durden2.0:对,您仍然必须手动添加内容。但在这种情况下,您可以将其添加到 QtCore.QObject 对象中(前提是它是纯 Python 类),而无需更改其源代码。
    • 好点。但是,QtCore.QObject 不是纯 Python 类。我相信它实际上是来自sip 的自动生成的代码。我刚刚对此进行了测试,它有点工作了一秒钟,但导致了段错误。 :)
    • 我相信段错误是由于替换了QtCore.QObject.__init__。不过我有点困惑,因为我保存了原件并完全按照以前的方式调用它。猜测它是 C++ 包装层的问题,但使用 gdb 运行并没有给我任何好的信息。
    • 我会接受这个答案,因为它技术上应该可以工作。但是,我认为我的装饰器中存在错误 QtCore.QObject 上替换 __init__ 是不允许的。无论如何,如果这种行为在QtCore.QObject 上实际上是可能的,我认为这个答案代表了实现我想要的最佳方式。如果您有兴趣,我已经向related question 询问了装饰器段错误。
    猜你喜欢
    • 2011-07-25
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 2019-12-24
    相关资源
    最近更新 更多