考虑以下装饰器
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__
方法。
为什么会出现这种差异?还有一种方法可以在我的班级风格装饰器中获取对象吗?
答案 0 :(得分:2)
self
仅适用于因为方法包含在descriptors中。当请求obj.meth
,在对象中找不到然后在类中找到时,使用包括对象在内的一些信息调用描述符的__get__
方法,并返回实际方法对象周围的包装器,当调用,使用对象调用底层方法作为additonal / first参数(self
)。
这些描述符仅为实际功能添加,而不是为其他可调用对象添加。要使使用__call__
方法的类像方法一样工作,您必须实现__get__
方法(请参阅上面的链接)。