在python中有两种声明装饰器的方法:
基于类
class mydecorator(object):
def __init__(self, f):
self.f = f
def __call__(self, *k, **kw):
# before f actions
self.f(*k, **kw)
# after f actions
基于功能
def mydecorator(f):
def decorator(*k, **kw):
# before f actions
f(*k, **kw)
# after f actions
return decorator
这些声明之间有什么区别吗? 在哪些情况下应该使用它们?
答案 0 :(得分:19)
如果你想在装饰器中保持状态,你应该使用一个类。
例如,这不起作用
def mydecorator(f):
x = 0
def decorator():
x += 1 # x is a nonlocal name and cant be modified
return f(x)
return decorator
有很多解决方法,但最简单的方法是使用类
class mydecorator(object):
def __init__(self, f):
self.f = f
self.x = 0
def __call__(self, *k, **kw):
self.x += 1
return f(self.x)
答案 1 :(得分:19)
当您创建一个可调用的函数返回另一个可调用函数时,函数方法更容易,更便宜。有两个主要区别:
__get__
方法。此外,函数方法允许您在修改或存储原始函数后返回它。
然而,装饰者可以返回除可调用之外的其他内容或更多而不是可调用的内容。通过课程,您可以:
classmethod
,property
)如果您有任何疑问,请问自己:您是否希望装饰者返回一个功能完全像函数应该的功能?使用返回函数的函数。您是否希望装饰器返回一个自定义对象,该对象可以执行更多功能或与功能不同的功能?创建一个类并将其用作装饰器。
答案 2 :(得分:6)
事实上,没有“两种方式”。只有一种方法(定义一个可调用对象)或者在python中创建一个可调用对象的方法(它可以是其他对象的方法,lambda表达式的结果,'部分'对象,任何是可调用)。
函数定义是制作可调用对象的最简单方法,并且作为最简单的方法,在大多数情况下可能是最好的。使用类为您提供了更多可能来干净地编写更复杂的案例(即使在最简单的情况下它看起来相当优雅),但它的作用并不明显。
答案 3 :(得分:2)
不,有两种方法可以制作可调用对象。一个是def
一个函数,它显然是可调用的。另一种方法是在类中定义一个__call__
方法,这将使它的实例可以调用。类本身是可调用的对象。
装饰器只不过是一个可调用对象,意图接受一个函数作为其唯一参数并返回一些可调用的东西。语法如下:
@decorate
def some_function(...):
...
只是一种更好的写作方式:
def some_function(...):
...
some_function = decorate(some_function)
你给出的基于类的例子不是一个函数,它接受一个函数并返回一个函数,它是一个标准的vanilla decorator,它是一个用一个实例初始化的类,它的实例是可调用的。对我来说,如果你实际上并没有将它作为一个类使用它,这有点奇怪(它是否有其他方法?它的状态是否会发生变化?你是否制作了几个具有由类封装的常见行为的实例?)。但正常使用你的装饰功能并不能说明差异(除非它是一个特别具有侵略性的装饰者),所以对你来说感觉更自然。
答案 4 :(得分:1)
我们来试试吧!
test_class = """
class mydecorator_class(object):
def __init__(self, f):
self.f = f
def __call__(self, *k, **kw):
# before f actions
print 'hi class'
self.f(*k, **kw)
print 'goodbye class'
# after f actions
@mydecorator_class
def cls():
print 'class'
cls()
"""
test_deco = """
def mydecorator_func(f):
def decorator(*k, **kw):
# before f actions
print 'hi function'
f(*k, **kw)
print 'goodbye function'
# after f actions
return decorator
@mydecorator_func
def fun():
print 'func'
fun()
"""
if __name__ == "__main__":
import timeit
r = timeit.Timer(test_class).timeit(1000)
r2 = timeit.Timer(test_deco).timeit(1000)
print r, r2
我有这样的结果:0.0499339103699 0.0824959278107
这意味着类装饰速度快2倍?