【问题标题】:Are decorators that are classes called different than decorators that are functions?作为类的装饰器与作为函数的装饰器是否不同?
【发布时间】:2011-09-30 11:33:35
【问题描述】:

考虑以下装饰器

class MethodDecoratorC(object):
    def __init__(self,func):
        self.func = func
    def __call__(self,*args,**kwargs):
        print(len(args))
        print(len(kwargs))
        self.func(*args,**kwargs)

def method_decorator_f(func):
    def wrapped_func(*args,**kwargs):
        print(len(args))
        print(len(kwargs))
        func(*args,**kwargs)
    return wrapped_func

它们看起来完全一样,而且功能也确实如此:

@MethodDecoratorC
def test_method_c(a):
    print(a)

@method_decorator_f
def test_method_f(a):
    print(a)

test_method_f("Hello World! f")
test_method_c("Hello World! c")

打印:

1
0
Hello World! f
1
0
Hello World! c

然而,对于方法,发生了一些非常奇怪的事情:

class TestClass(object):
    @MethodDecoratorC
    def test_method_c(self,a):
        print(a)

    @method_decorator_f
    def test_method_f(self,a):
        print(a)

t = TestClass()
t.test_method_f("Hello World! f")
t.test_method_c("Hello World! c")

打印:

2
0
Hello World! f
1
0
Traceback (most recent call last):
  File "test5.py", line 40, in <module>
    t.test_method_c("Hello World! c")
  File "test5.py", line 8, in __call__
    self.func(*args,**kwargs)
TypeError: test_method_c() takes exactly 2 arguments (1 given)

没有太大的期望!不知何故,TestClass 对象没有作为参数传递给我的装饰器对象的 __call__ 方法。

为什么会有这种差异?有没有办法让我仍然可以在我的类风格装饰器中获取对象?

【问题讨论】:

    标签: python-3.x decorator


    【解决方案1】:

    self 绑定到实例方法的第一个参数仅是因为方法包含在 descriptors 中。当obj.meth 被请求时,在对象中没有找到然后在类中找到,描述符的__get__ 方法被调用,其中包含一些包括对象在内的信息,并返回一个围绕实际方法对象的包装器,当被调用时,调用以对象作为附加/第一个参数的底层方法 (self)。

    这些描述符只为实际函数添加,不为其他可调用对象添加。要使带有__call__ 方法的类像方法一样工作,您必须实现__get__ 方法(参见上面的链接)。

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 2021-06-24
      • 2019-02-20
      • 2011-10-04
      • 2021-07-16
      • 1970-01-01
      • 2014-02-18
      • 2019-01-01
      • 1970-01-01
      相关资源
      最近更新 更多