【问题标题】:Why is there no argument when returning function in a decorator.为什么在装饰器中返回函数时没有参数。
【发布时间】:2016-11-09 15:28:34
【问题描述】:
示例:
带有 memoize 装饰器的斐波那契递归函数。调用函数助手时没有参数。如果函数助手被定义为采用参数 x 因此我希望使用一个参数调用该函数。我想了解为什么语法是这样的?
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
@memoize
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
print(fib(40))
【问题讨论】:
标签:
python
function
arguments
decorator
memoization
【解决方案1】:
您确实使用参数调用了助手。装饰器是这个的语法糖
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
fib = memoize(fib)
所以您的fib 函数不再是原来的fib 函数。它实际上是 helper 闭包,因为这就是 memoize 返回的 - 一个闭包。所以,当你打电话给fib(40) 时,你会打电话给helper(40)。 memoize 装饰器创建一个函数对象,它不调用它,只是返回它。
【解决方案2】:
我相信语法是这样的,因此它看起来尽可能精简。您在@(一个接受一个参数并返回一个函数的函数)之后放置一个装饰器对象,python 使用您定义的函数调用它。这个
@memoize
def fib(n):
...
完全等价于以下,不使用魔法装饰器语法:
def fib(n):
...
fib = memoize(fib)
如果你想让你的头脑稍微转动一下,考虑@ 实际上可以跟一个函数调用——但是这个函数调用必须返回一个像上面那样工作的装饰器!这是一个愚蠢的示例,它计算了装饰函数被调用的次数,但允许您设置起始值。 (这只是一个例子:它不是很有用,因为只能装饰一个函数等)
def countcalls(start):
global _calls
_calls = start
def decorator(f):
def wrapper(x):
global _calls
_calls += 1
return f(x)
return wrapper
return decorator
@countcalls(3)
def say(s):
print(s)
say("hello")
# _calls is now 4
这里,countcalls(4) 定义并返回(不调用它)函数decorator,它将包装装饰函数并返回包装器来代替我编写的函数。