1

我过去使用过装饰器没有任何问题,但我坚持使用这个。似乎当我的装饰函数被 PyQt 操作调用时,它失败了。我的理论是 PyQt 以某种方式在内部包装了连接的函数并弄乱了签名或类似的东西,但我找不到任何证据。

连接我的意思是这样的:

from PyQt4 import QtGui

# In my widget init...
self.action_my_method = QtGui.QAction("action_my_method", self)
self.action_my_method.triggered.connect(self.my_method)

这是我的简单装饰器:

from functools import wraps

def simple_decorator(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        from inspect import getargspec
        print getargspec(fn)

        return fn(*args, **kwargs)
    return wrapper

当我用它来装饰一个没有任何参数(def my_method(self))的方法,并直接从我的 QWidget 类中执行它时,它工作正常。当我使用菜单触发操作时,我得到:

# Traceback (most recent call last):
#   File "[...].py", line 88, in wrapper
#     return fn(*args, **kwargs)
# TypeError: my_method() takes exactly 1 argument (2 given)

我看到了一个 arg 规范:

ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None)

如果我添加*args到我的方法中,所以签名是my_method(self, *args),装饰器工作正常并且 arg 规范是:

ArgSpec(args=['self'], varargs='args', keywords=None, defaults=None)

我在这里看不到任何线索,因为装饰器在直接调用时可以正常工作,但在被操作触发时会失败。

任何人都可以对此有所了解,或者提供一些我可以用来进一步调试它的东西吗?

4

2 回答 2

1

这与其说是一个解决方法,不如说是一个答案。我希望这没有任何不利之处。我在输入一个简单的重定向功能时想到了它。这使用 lambda 在运行时做同样的事情:

self.action_my_method.triggered.connect(lambda: self.my_method())

这足以使我的装饰功能免受损坏并防止错误。

于 2012-06-13T22:07:51.860 回答
0

或者,您可以将可以通过 .connect 调用的每个方法的签名重新定义为:

def my_method(self, qtcallparam=None, **kwargs):

所以该方法将忽略第一个未命名的参数,代价是在该方法中使用严格的关键字参数(不是一件坏事)

但是@Rafe 的解决方案可能更干净

于 2017-01-18T08:24:30.873 回答