调用装饰函数两次将仅返回装饰器,而不返回该函数

时间:2020-01-10 21:17:29

标签: python-3.x python-decorators

这是我定义定时装饰器的代码:

from functools import wraps, lru_cache

def timed(fn):
    from time import perf_counter

    @wraps(fn)
    def inner(*args,**kwargs):
        start = perf_counter()
        result = fn(*args,**kwargs)
        end = perf_counter()
        timer = end - start

        fs = '{} took {:.3f} microseconds'
        print(fs.format(fn.__name__, (end - start) * 1000000))

        return result
    return inner

这是函数定义:

@timed
@lru_cache
def factorial(n):
    result = 1
    cache = dict()
    if n < 2:
        print('Calculating factorial for n > 1')

        result = 1
        print(f'factorial of {result} is {result}')

    else:
        for i in range(1,n+1):
            if i in cache.items():
                result = cache[i]
                #print(f'factorial of {i} is {result}')
            else:
                result *= i
                cache[i] = result

        print(f'factorial of {i} is {result}')
            #print(f'{cache}')
    return result

以下是对函数的调用:

阶乘(3)

阶乘(10)

阶乘(10)

这是输出

factorial of 3 is 6
factorial took 32.968 microseconds
factorial of 10 is 3628800
factorial took 11.371 microseconds
**factorial took 0.323 microseconds**

问题: 为什么当我第二次调用factorial(10)时,没有打印输出?

2 个答案:

答案 0 :(得分:2)

因为lru_cache的全部要点是缓存函数的参数和与它们关联的返回值,并最小化装饰函数的实际执行次数

当您第二次调用factorial(10) 时,不会调用该函数,而是从缓存中获取该值。这也是为什么第二次调用快 35倍的原因-因为甚至没有调用该函数,而这正是functools.lru_cache的目的。

答案 1 :(得分:1)

您只想缓存 pure 函数;您的阶乘不纯,因为它有写入标准输出的副作用。

对于所需的行为,请定义两个函数:您缓存的纯函数和使用该纯函数的不纯包装。

@lru_cache
def factorial_math(n):
    result = 1
    for i in range(2, n):
        result *= i
    return result

@timed
def factorial(n):
    result = factorial_math(n)
    print(f'factorial of {n} is {result}')
    return result