【问题标题】:Understanding this Python decorator code理解这个 Python 装饰器代码
【发布时间】:2017-05-04 23:51:31
【问题描述】:

我在理解从“Learning Python”部分装饰器中获得的这段代码时遇到了问题。

为什么这段代码返回结果的变量值一次而不是两次?我们两次返回结果变量的数量,一次在“max_result”中,另一次在“measure”中;这是代码:

from time import sleep, time
from functools import wraps

def measure(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        t = time()
        result = func(*args, **kwargs)
        print(func.__name__, 'took:', time() - t)
        return result
    return wrapper

def max_result(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        if result > 100:
            print('Result is too big ({0}). Max allowed is 100.'
                  .format(result))
        return result
    return wrapper

@measure
@max_result
def cube(n):
    return n ** 3

print(cube(2))
print(cube(5))

这是输出,为什么我们不得到两个 8 或两个 125?

>>> print(cube(2))
cube took: 8.106231689453125e-06
8
>>> print(cube(5))
Result is too big (125). Max allowed is 100.
cube took: 5.91278076171875e-05
125
>>> 

【问题讨论】:

  • 为什么你认为你应该得到两个 8?
  • 只涉及三个打印语句,每个语句最多执行一次。
  • boock 说:“在第二次调用时,结果为 125 ,因此打印错误消息,返回结果,然后轮到 measure ,再次打印运行时间,并且最后,我们打印结果(125)。”所以我们两次返回结果其中之一发生了什么?

标签: python decorator python-decorators


【解决方案1】:

装饰器是链式的。原来的cube() 函数被max_result 装饰器包裹,而那个装饰的resultmeasure 装饰。

所以cube() 的返回值被max_result() 中的wrapper() 获取,该函数的结果被measure() 中的wrapper() 获取,然后返回给调用者。

解开所有装饰器会给你:

def measure_wrapper(*args, **kwargs):
    t = time()
    result = max_result_wrapper(*args, **kwargs)
    print(func.__name__, 'took:', time() - t)
    return result

def max_result_wrapper(*args, **kwargs):
    result = original_cube(*args, **kwargs)
    if result > 100:
        print('Result is too big ({0}). Max allowed is 100.'
              .format(result))
    return result

def original_cube(n):
    return n ** 3

cube = measure_wrapper

所以调用cube(2) 会产生:

  • measure_wrapper(2),记录t = time()和电话
    • max_result_wrapper(2),直接调用
      • original_cube(2),其中
      • 返回2 ** 38
    • 测试8 > 100,这是错误的,所以
    • 返回8
  • 打印max_result_wrapper()调用的时间和
  • 返回8

【讨论】:

  • 谢谢你的回答,我现在完全明白了。
猜你喜欢
  • 1970-01-01
  • 2016-12-01
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 2021-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多