为什么在装饰器中返回函数时没有参数。

时间:2016-07-07 10:36:15

标签: python function arguments decorator memoization

实施例: 具有memoize装饰器的Fibonaci递归函数。调用函数助手时没有参数。如果函数助手被定义为接受参数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))

2 个答案:

答案 0 :(得分:2)

您可以使用参数调用帮助程序。装饰者是这个

的语法糖
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装饰器创建一个函数对象,它不会调用它,只返回它。

答案 1 :(得分:0)

我相信语法是这样的,所以它看起来尽可能简化。你在@(一个接受一个参数的函数,并返回一个函数)之后放置一个装饰器对象,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,它将包装装饰函数并返回包装器来代替我写的函数。