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

我试图让我的基于类的装饰器保持原始包装函数的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__中的属性,但将任何特殊方法作为代理.

上一篇:如何在依赖注入框架(PicoContainer)中注册装饰对象?


下一篇:python – 我可以获得应用于函数的装饰器列表吗?