我试图让我的基于类的装饰器保持原始包装函数的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(instance)
实际上调用了instance.__class__.__repr__(instance)
。因此,永远不会调用实例的重写__repr__
方法。
所以这是我的问题:
repr(instance)
拨打instance.__class__.__repr__(instance)
而不是instance.__repr__()
?或者我错过了其他什么?functools.wraps
完全复制到基于类的装饰器(包括更改装饰函数上repr()
调用的结果)?答案 0 :(得分:6)
特殊方法是always looked up on the type of the instance(这里是类对象),而不是实例。否则,当您尝试打印类本身的表示时,将使用类上的__repr__
; type(class).__repr__(class)
会使用正确的魔术方法,而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)
e.g。仍然复制__module__
,__name__
和__doc__
属性,并复制函数__dict__
中的属性,但将任何特殊方法作为代理。