如何实际定义python装饰器?

时间:2017-11-25 14:16:20

标签: python decorator

首先,我知道装饰者是什么。我想了解一些小方面。

TL; DR

is decorator func1 = func2(func1) # True
is decorator func3 = func2(func1) # ???

让我们看一下Wiki,它描述了两种等效的装饰函数的方法:

@viking_chorus
def menu_item():
    print("spam")

def menu_item():
    print("spam")
menu_item = viking_chorus(menu_item)

现在,让我们看一下这个website的描述,特别是回到装饰者部分。定义了两个函数:

def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner

def ordinary():
    print("I am ordinary")

然后作者装饰该函数并调用它:

>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary

我们可以注意到作者没有使用:

>>> ordinary = make_pretty(ordinary)

这是Wiki推荐的方式(我知道Wiki有时可能是错误的)。所以我决定使用最后一种方法来装饰从tutorial取得的Fibonacci数字函数:

def memoize(f):
    memo = {}
    def helper(x):
        if x not in memo:            
            memo[x] = f(x)
        return memo[x]
    return helper


def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

这个电话:

>>> fib_element = memoize(fib)
>>> fib_element(40)

在我的机器上花费很长时间,这意味着fib()未正确装饰。执行时间与fib(40)相当。这些电话:

>>> fib = memoize(fib)
>>> fib_element = fib # assigned after decoration
>>> fib(40)
>>> fib_element(40)

快速执行。所以问题是:我们可以说我们在ordinary作业中装饰了pretty = make_pretty(ordinary)函数吗?

1 个答案:

答案 0 :(得分:2)

第一次调用fib_element(40)的原因是你没有递归装饰:fib函数不知道你的memoization。如果你在同一个元素上反复调用fib_element,第一个调用会很慢,其他调用会非常快。

由于fib调用fib(它引用第二个示例中的修饰函数,但是第一个示例中的原始函数),因此需要为其提供相同的名称以便从memoization中获益这种装饰方法。