【问题标题】:Calling a decorated function twice returns only the decorator and not the function调用装饰函数两次只返回装饰器而不返回函数
【发布时间】:2020-04-28 13:02:36
【问题描述】:

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

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) 时没有打印出来?

【问题讨论】:

  • 你为什么使用lru_cache维护你自己的缓存?
  • 我应该把它拿出来吗?

标签: python-3.x python-decorators


【解决方案1】:

因为lru_cache 的全部意义在于缓存函数的参数和与之关联的返回值,并最小化修饰函数的实际执行次数

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

【讨论】:

    【解决方案2】:

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

    对于您想要的行为,定义两个函数:一个您缓存的纯函数,以及一个使用纯函数的不纯包装器。

    @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
    

    【讨论】:

      猜你喜欢
      • 2016-10-20
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      • 2019-05-31
      • 2021-06-24
      • 1970-01-01
      相关资源
      最近更新 更多