正确调用修饰函数

时间:2021-04-15 13:04:12

标签: python python-decorators

我试图从另一个类中重复调用装饰函数,以便每次调用该函数时都会执行装饰器。

原始问题如下,但没有明确指出正确指出的 pyqt。

我正在尝试在 pyqt 线程中使用装饰器。从我对装饰器的理解来看,每次调用函数时都应该执行装饰。 (或者至少这是我想要的。)但是,从 pyqt 线程中调用装饰函数会导致装饰器只执行一次。

这是我测试过的例子:

import time, sys
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


class Decor:

    def deco(self, *args, **kwargs):
        print(kwargs['txt'])
        print("In decorator")

        def inner(func):
            return func

        return inner


dec = Decor()


class Window(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.thread = Worker()
        label = QLabel(self.tr("random number"))
        self.thread.output[str].connect(label.setText)
        layout = QGridLayout()
        layout.addWidget(label, 0, 0)
        self.setLayout(layout)
        self.thread.start()


class Worker(QThread):
    output = pyqtSignal(str)

    def run(self):
        # Note: This is never called directly. It is called by Qt once the
        # thread environment has been set up.
        while True:
            time.sleep(1)
            number = self.random()
            self.output.emit('random number {}'.format(number))

    @dec.deco(txt='kw_argument')
    def random(self):
        return np.random.rand(1)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

我希望在调用 self.normal() 时经常获取 'kw_argument' 和 'in decorator' 的打印,但只获取一次。我做错了什么?

1 个答案:

答案 0 :(得分:1)

你可以改用函数装饰器:

import time, sys
from functools import wraps
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


def dec2(*args, **kwargs):
    def real_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            print(args, kwargs)
            print("In decorator")
            return fn(*args, **kwargs)

        return wrapper

    return real_decorator


class Window(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.thread = Worker()
        label = QLabel(self.tr("random number"))
        self.thread.output[str].connect(label.setText)
        layout = QGridLayout()
        layout.addWidget(label, 0, 0)
        self.setLayout(layout)
        self.thread.start()


class Worker(QThread):
    output = pyqtSignal(str)

    def run(self):
        # Note: This is never called directly. It is called by Qt once the
        # thread environment has been set up.
        while True:
            time.sleep(1)
            number = self.random()
            self.output.emit('random number {}'.format(number))

    @dec2(txt='kw_argument')
    def random(self):
        return np.random.rand(1)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

出:

(<__main__.Worker object at 0x10edc37d0>,) {}
In decorator
(<__main__.Worker object at 0x10edc37d0>,) {}
In decorator
(<__main__.Worker object at 0x10edc37d0>,) {}
In decorator
(<__main__.Worker object at 0x10edc37d0>,) {}
In decorator
(<__main__.Worker object at 0x10edc37d0>,) {}
In decorator
...

如果您确实需要始终打印 txt,请坚持使用类装饰器:

class dec2(object):
    def __init__(self, *args, **kwargs):
        self.deco_args = args
        self.deco_kwargs = kwargs

    def __call__(self, f):
        def wrapped_f(*args):
            print(self.deco_kwargs['txt'])
            print('in decorator')
            return f(*args)

        return wrapped_f

出:

w_argument
in decorator
kw_argument
in decorator
...
相关问题