示例代码:
# -*- coding: utf-8 -*-
from functools import wraps
class MyClass(object):
def __init__(self):
pass
#decorator inside class
def call(f):
@wraps(f)
def wrapper(*args):
print 'Wrapper: ', args
return wrapper
#decorated 'method' without self
@call
def myfunc(a):
pass
c = MyClass()
c.myfunc(1)
返回:
Wrapper: (<test3.MyClass object at 0xb788a34c>, 1)
这正常吗?有人可以解释一下吗?
如果这是一个功能,我会在我的库中使用它。
最佳答案
这是完全正常的。
函数myfunc
被 wrapper
的实例替换。 wrapper
的签名是 (*args)
。因为它是一个绑定(bind)方法,所以第一个参数是 MyClass
的实例它在字符串“Wrapper:”之后打印出来。
什么让你感到困惑?
值得注意的是,如果你使用call
作为MyClass
外部的装饰器,它会生成一个 TypeError
。解决这个问题的一种方法是应用 staticmethod
装饰器,但你不能在类构造期间调用它。
这有点hacky,但我解决了如何同时拥有它here .
评论后更新
无论您是否输入self
,它都会将实例作为第一个参数在参数列表中,因为在创建类并实例化实例之后,它是一个绑定(bind)方法。当您以表单调用它时
@instance.call
def foo(bar):
return bar + 1
它扩展为
def foo(bar):
return bar + 1
foo = instance.call(f)
但请注意,您是在实例上调用它!这将自动扩展为以下形式的调用
def foo(bar):
return bar + 1
foo = MyClass.call(instance, f)
这就是方法的工作原理。但你只定义了call
接受一个参数,因此这会引发 TypeError
.
至于在类构造期间调用它,它工作得很好。但它返回的函数传递了 MyClass
的实例当 it 被调用时,原因与我上面解释的相同。具体来说,无论您显式传递给它的什么参数,都会在将调用的实例隐式且自动放置在参数列表的前面之后出现。
关于python - 类内的装饰器和没有 'self' 的装饰类方法给出了奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3808967/