修饰器仅在首次定义修饰函数之后被调用一次。因此,这两种技术(使用@wrap和巴=涡卷(巴))是相同的:
>>> def wrap(f):
... print 'making arr'
... arr = []
... def inner():
... arr.append(2)
... print arr
... f()
... return inner
...
>>> @wrap
... def foo():
... print 'foo was called'
...
making arr
>>> foo()
[2]
foo was called
>>> foo()
[2, 2]
foo was called
>>> def bar():
... print 'bar was called'
...
>>> bar = wrap(bar)
making arr
>>> bar()
[2]
bar was called
在两种情况下很明显,ARR创建只有当涡卷(F)被调用,并且是包装只有当foo和bar第一次被声明时才被调用。
至于将参数传递给装饰函数的情况,请记住装饰器将函数作为参数并返回该函数的修改版本。所以装饰器通常需要一个参数,这是它正在修改的函数。它返回一个新的函数,装饰器可以定义它返回的函数作为任意数量的参数(例如* args)。装饰器甚至可以返回一个函数,它为装饰的方法带来太多参数。
>>> def wrap_with_arg(f):
... def wrap(*args):
... print 'called with %d arguments' % len(args)
... f(args)
... return wrap
...
>>> @wrap_with_arg
... def baz(arg):
... print 'called with argument %r' % arg
...
>>> baz(3)
called with 1 arguments
called with argument 3
>>> baz(3, 4)
called with 2 arguments
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in wrap
File "<input>", line 3, in baz
TypeError: not all arguments converted during string formatting
虽然最终baz抛出一个错误,请注意如何在抛出错误之前正确打印参数的数量。
+1很好的答案。 – 2012-04-04 12:51:32
+1,有趣的是提到正在创建闭包,这就是为什么当函数defm已经被返回时可以访问'cache'。 – mmarinero 2012-04-04 13:02:33
谢谢,现在我理解装饰器好多了! :) – 2012-04-05 07:14:34