在下面的代码中,我为类Class
方法创建了一个装饰器。我注意到,即使不创建类实例也将调用此装饰器!
而且无需在类中调用这些方法!
对此有什么解释吗?
def deco(class_name):
def inner_function(method):
print("method is = {} and class is: {}".format(method.__name__,class_name.__name__))
return method
return inner_function
class class_deco :
def __init__(self):
pass
class Class :
def __init__(self):
pass
@deco(class_deco)
def f1(self):
pass
@deco(class_deco)
def f2(self):
pass
当我运行脚本时:
if __name__ == "__main__":
pass
我得到这个结果:
method is = f1 and class is: class_deco
method is = f2 and class is: class_deco
答案 0 :(得分:2)
装饰者只是以下人群的合成糖
@deco(class_deco)
def f1(self):
pass
与-
相同f1 = deco(class_deco)(f1)
因此,该代码在导入模块后立即运行,就像其他任何名称声明一样,并且f1
名称如上所述被修饰的f1替换。
答案 1 :(得分:2)
如前所述,@decorator
语法只是语法糖,因此:
@somedecorator
def foo():
pass
严格等同于
def foo():
pass
foo = somedecorator(foo)
在这种情况下,您将显式调用装饰器函数:
@deco(class_deco)
def f1(self):
pass
等效于:
def f1(self):
pass
_effective_decorator = deco(class_deco)
f1 = _effective_decorator(f1)
这就是为什么inner_function
确实在导入时执行的原因。
采用其他参数的装饰器需要多层嵌套,因此从技术上讲,装饰器应如下所示:
def deco(cls):
def real_deco(func):
def inner_function(*args, **kw):
print("method is = {} and class is: {}".format(func.__name__,cls.__name__))
return func(*args, **kw)
return inner_function
return real_deco
return inner_function
但是如果要获取方法确实所属的类的名称,这仍然是无效的-您应该从调用该方法的实例中获取该类,而不是尝试在装饰器调用中对其进行硬编码(这将永远无法按预期工作,因为在将装饰器应用于函数时,实际类并不存在)。因此正确的实现应类似于:
def deco(func):
# we're only supposed to use this on methods...
def wrapper(self, *args, **kw):
print("class {} - method {}".format(type(self).__name__, func.__name__))
return wrapper
class Class:
@deco
def f1(self):
pass
注意:这当然不会处理类方法或静态方法。
答案 2 :(得分:1)
这里是一个演示,展示了仅两种可能的构造装饰器的方式:
def Deco(*deco_params):
print('In Deco', deco_params)
def deco(func):
print('In deco(func)')
def inner(*args, **kwargs):
print('In inner(*args, **kwargs)')
return func(*args, **kwargs)
return inner
return deco
def deco(method):
print('In deco(method)')
def inner_function(*args, **kwargs):
print("method is = {} called".format(method.__name__))
return method(*args, **kwargs)
return inner_function
class Class :
def __init__(self):
pass
@deco
def f1(self):
pass
@Deco(42)
def f2(self):
pass
if __name__ == "__main__":
print('Now in Main')
c = Class()
c.f1()
c.f2()
输出:
In deco(method)
In Deco (42,)
In deco(func)
Now in Main
method is = f1 called
In inner(*args, **kwargs)