我想这就是他们被调用的方式,但我会举例说明。
装饰者类:
class decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print 'something'
self.func(*args, **kwargs)
装饰功能:
def decorator(func):
def wrapper(*args, **kwargs):
print 'something'
return func(*args, **kwargs)
return wrapper
使用其中一种只是品味问题?有什么实际区别吗?
答案 0 :(得分:13)
如果您可以编写一个函数来实现装饰器,那么您应该更喜欢它。但并非所有装饰器都可以轻松编写为函数 - 例如,当您想要存储某些内部状态时。
class counted(object):
""" counts how often a function is called """
def __init__(self, func):
self.func = func
self.counter = 0
def __call__(self, *args, **kwargs):
self.counter += 1
return self.func(*args, **kwargs)
@counted
def something():
pass
something()
print something.counter
我见过人们(包括我自己)经历了荒谬的努力,只能用功能来编写装饰器。我仍然不知道为什么,一个班级的开销通常完全可以忽略不计。
答案 1 :(得分:3)
这通常只是品味问题。大多数Python程序使用duck typing并不关心他们调用的东西是函数还是其他类型的实例,只要它是可调用的。任何__call__()
方法都可以调用。
使用函数式装饰器有一些优点:
当装饰者没有返回包装函数时(例如,在对其执行某些操作后返回原始函数,例如设置属性),会更清晰。
无需显式保存对原始函数的引用,因为这是由闭包完成的。
大多数帮助您制作装饰器的工具,例如functools.wraps()
或Michele Simionato的保留签名decorator
模块,都可以使用函数式装饰器。
可能有一些程序在那里不使用duck typing,但实际上期望一个函数类型,所以返回一个函数来替换一个函数在理论上是“更安全的”。
由于这些原因,我大多数时候都使用函数式装饰器。然而,作为一个反例,here是一个最近的例子,其中类风格的装饰对我来说更自然。
答案 2 :(得分:0)
提议的类装饰器实现与函数实现略有不同:它会在方法上失败
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('something')
self.func(*args, **kwargs)
class A:
@Decorator
def mymethod(self):
print("method")
A().mymethod()
将提高 TypeError: mymethod() missing 1 required positional argument: 'self'
要添加对方法的支持,您需要实现 __get__
import types
class Decorator2(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('something')
self.func(*args, **kwargs)
def __get__(self, instance, owner):
if instance is None:
return self
return types.MethodType(self, instance)
class B:
@Decorator2
def mymethod(self):
print("method")
B().mymethod()
会输出
B 类:...
something
method
它起作用的原因是当您访问 B().mymethod
时,首先调用 __get__
并提供绑定方法。然后 __call__
被调用
总而言之,如果您定义了 __get__
,类和函数实现可以以相同的方式使用。有关详细信息,请参阅 Python 食谱配方 9.9。