【问题标题】:Class-based decorator and repr() conservation基于类的装饰器和 repr() 守恒
【发布时间】:2014-03-12 19:40:45
【问题描述】:

我试图让基于类的装饰器保持原始包装函数的 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() 对装饰函数的调用的结果)?

【问题讨论】:

    标签: python python-3.x decorator python-decorators repr


    【解决方案1】:

    特殊方法是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)
    

    例如仍然复制 __module__、__name__ 和 __doc__ 属性,并从函数 __dict__ 复制属性,但将任何特殊方法设为代理。

    【讨论】:

      猜你喜欢
      • 2014-10-20
      • 2023-03-17
      • 2017-03-08
      • 1970-01-01
      • 2017-03-24
      • 2016-08-18
      • 2023-03-14
      • 2020-07-07
      • 2011-06-06
      相关资源
      最近更新 更多