最近我一直在写一些装饰者。 我刚写的其中一个允许你将装饰器放在类定义之前,它会导致类的每个方法在运行时打印一些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分钟添加空格,但它出错了......对不起!)
答案 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()
(当然,只需用上面的花式记录器替换基本记录器)