基于类的装饰器和repr()保护

Max*_*ini 3 python repr decorator python-3.x python-decorators

我试图让我的基于类的装饰器保持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
Run Code Online (Sandbox Code Playgroud)

但是当我调用repr()装饰函数时,我得到:

>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b6850>'
Run Code Online (Sandbox Code Playgroud)

很好,所以我试着自定义__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)
Run Code Online (Sandbox Code Playgroud)

不会改变输出,但会发生一些有趣的事情:

>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b69d0>'
>>> wrapped.__repr__()
'<function wrapped at 0x2d8860a9710>'
Run Code Online (Sandbox Code Playgroud)

显式设置__repr__装饰器实例的方法具有相同的效果.

经过一些测试后,我推断出了repr(instance)实际调用instance.__class__.__repr__(instance).因此,__repr__永远不会调用实例的overriden 方法.


所以这是我的问题:

  • 为什么要repr(instance)打电话instance.__class__.__repr__(instance)而不是instance.__repr__()?还是我错过了别的什么?
  • 如何完全重现functools.wraps基于函数的装饰器对基于类的装饰器的作用(包括改变repr()装饰函数调用的结果)?

Mar*_*ers 6

特殊方法总是在实例的类型(这里是类对象)上查找,而不是在实例上查找.否则__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)
Run Code Online (Sandbox Code Playgroud)

例如,仍然复制__module__,__name____doc__属性,并从函数复制属性__dict__,但使任何特殊方法成为代理.