继承自另一个类时的类装饰器

时间:2018-01-18 02:22:08

标签: python inheritance decorator python-decorators

最近我一直在写一些装饰者。 我刚写的其中一个允许你将装饰器放在类定义之前,它会导致类的每个方法在运行时打印一些logigng信息(更多用于构建期间的调试/初始超级基本速度测试)

with open

这适用于我创建的非常基本的类。

当我开始遇到问题时,我将它应用于继承另一个的类 - 例如,使用QT:

def class_logit(cls):

    class NCls(object):
        def __init__(self, *args, **kwargs):
            self.instance = cls(*args, **kwargs)

        @staticmethod
        def _class_logit(original_function):
            def arg_catch(*args, **kwargs):
                start = time.time()
                result = original_function(*args, **kwargs)

                print('Called: {0} | From: {1} | Args: {2} | Kwargs: {3} | Run Time: {4}'
                  ''.format(original_function.__name__, str(inspect.getmodule(original_function)),
                            args, kwargs, time.time() - start))
                return result

            return arg_catch

        def __getattribute__(self, s):
            try:
                x = super(NCls, self).__getattribute__(s)
            except AttributeError:
                pass
            else:
                return x
            x = self.instance.__getattribute__(s)
            if type(x) == type(self.__init__):
                return self._class_logit(x)
            else:
                return x

    return NCls

我得到以下错误......我不完全确定该怎么做!

@scld.class_logit
class TestWindow(QtGui.QDialog):
    def __init__(self):
        print self
        super(TestWindow, self).__init__()
a = TestWindow()

任何帮助将不胜感激!

(道歉,无论我做什么,所以打破了我的第一段代码的格式......我甚至手动花了10分钟添加空格,但它出错了......对不起!)

1 个答案:

答案 0 :(得分:0)

你有点侵扰你的装饰者。

虽然如果你想要分析Qt框架本身定义的方法,但是需要一种有点激进的方法,你的装饰器会用代理替换整个类。

Qt绑定确实有点复杂,在这种情况下实例化时很难说出为什么会出错。

所以 - 首先要做的事情 - 如果你的意图是将装饰器应用于你自己定义的类层次结构,或者至少是纯Python中定义的类层次结构,那么可以使用元类的好方法:使用元类可以装饰创建类时的每个方法,并且在从每个类检索方法时不再在运行时混乱。

但是,与其他一些库一样,Qt在本机代码中定义了它的方法和类,这将阻止您在新类中包装现有方法。因此,将方法包装在__getattribute__上的属性检索上可以起作用。

这是一种更简单的方法,而不是使用代理,只需插入一个外部__getattribute__,它可以执行所需的包装记录器。
您的里程可能因此而异。特别是,如果本机代码中的其他方法调用了该类的一个方法,则不会触发它 - 因为这不会通过Python的属性检索机制(相反,它将使用C ++方法)直接检索。

from  PyQt5 import QtWidgets, QtGui

def log_dec(func):
    def wraper(*args, **kwargs):
        print(func.__name__, args, kwargs)
        return func(*args, **kwargs)
    return wraper


def decorate(cls):
    def __getattribute__(self, attr):
        attr = super(cls, self).__getattribute__(attr)
        if callable(attr):
            return log_dec(attr)
        return attr
    cls.__getattribute__ = __getattribute__
    return cls

@decorate
class Example(QtGui.QWindow):
    pass

app = QtWidgets.QApplication([])

w = Example()
w.show()

(当然,只需用上面的花式记录器替换基本记录器)