我试图让我的基于类的装饰器保持原始包装函数的repr()行为(以匹配functools.wraps装饰器在函数上的工作方式).我正在使用python 3.3.
首先我尝试了functools:
import functools
class ClassBasedDecorator():
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(self, fn)
def __call__(self, *args, **kwargs):
self.fn(*args, **kwargs)
@ClassBasedDecorator
def wrapped(text):
pass
但是当我在装饰函数上调用repr()时,我得到:
>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b6850>'
很好,所以我尝试自定义我的装饰器的__repr__方法,该方法应该由repr()调用.
再次使用functools:
class ClassBasedDecorator():
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(
self, fn,
assigned=functools.WRAPPER_ASSIGNMENTS + ('__repr__',)
)
def __call__(self, *args, **kwargs):
self.fn(*args, **kwargs)
不会改变输出,但会发生一些有趣的事情:
>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b69d0>'
>>> wrapped.__repr__()
'<function wrapped at 0x2d8860a9710>'
显式设置装饰器实例的__repr__方法具有相同的效果.
经过一些测试后我推断出repr(实例)实际上调用了实例.__ class __.__ repr __(实例).因此,永远不会调用实例的重写__repr__方法.
所以这是我的问题:
>为什么repr(实例)调用实例.__ class __.__ repr __(实例)而不是实例.__ repr __()?还是我错过了别的什么?
>你如何完全重现functools.wraps对基于类的装饰器的基于函数的装饰器的作用(包括改变装饰函数上的repr()调用的结果)?
解决方法:
特殊方法是always looked up on the type of the instance(这里是类对象),而不是实例.否则,当您尝试打印类本身的表示时,将使用类上的__repr__; type(class).__ repr __(class)将使用正确的magic方法,而class .__ repr __()会引发异常,因为没有提供self.
实现自己的__repr__钩子:
class ClassBasedDecorator():
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(self, fn)
def __call__(self, *args, **kwargs):
self.fn(*args, **kwargs)
def __repr__(self):
return repr(self.fn)
例如仍然复制__module __,_ ____和__doc__属性,并复制函数__dict__中的属性,但将任何特殊方法作为代理.