在没有 class 实例化的情况下调用 class 方法的装饰器?
decorators to class methods called without class instantiation?
在下面的代码中,我为 class Class
方法创建了一个装饰器。我注意到即使没有创建 class 实例也会调用这个装饰器!
并且没有在 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_deco
class class_deco :
def __init__(self):
pass
Class:
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
装饰器只是以下内容的语法糖
@deco(class_deco)
def f1(self):
pass
与 -
相同
f1 = deco(class_deco)(f1)
因此,此代码会在导入模块后立即运行,就像任何其他名称声明一样,并且 f1
名称将替换为上述修饰的 f1。
如前所述,@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
但是如果重点是获取 class 方法 真正 所属的名称,这仍然是错误的 - 你应该获取 class 来自调用该方法的实例,而不是尝试在装饰器调用中对其进行硬编码(这将永远不会按预期工作,因为当您将装饰器应用于功能)。所以正确的实现应该是这样的:
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
注意:这当然不会处理 class 方法和静态方法。
这里有一个演示,展示了装饰器的两种可能构建方式:
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)
在下面的代码中,我为 class Class
方法创建了一个装饰器。我注意到即使没有创建 class 实例也会调用这个装饰器!
并且没有在 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_deco
class class_deco :
def __init__(self):
pass
Class:
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
装饰器只是以下内容的语法糖
@deco(class_deco)
def f1(self):
pass
与 -
相同f1 = deco(class_deco)(f1)
因此,此代码会在导入模块后立即运行,就像任何其他名称声明一样,并且 f1
名称将替换为上述修饰的 f1。
如前所述,@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
但是如果重点是获取 class 方法 真正 所属的名称,这仍然是错误的 - 你应该获取 class 来自调用该方法的实例,而不是尝试在装饰器调用中对其进行硬编码(这将永远不会按预期工作,因为当您将装饰器应用于功能)。所以正确的实现应该是这样的:
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
注意:这当然不会处理 class 方法和静态方法。
这里有一个演示,展示了装饰器的两种可能构建方式:
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)