【问题标题】:Decorated function returns "None"装饰函数返回“无”
【发布时间】:2019-04-07 18:07:47
【问题描述】:

我对 python 非常陌生,我刚刚遇到了装饰器。我仍然对他们有点困惑,但我正在学习

我试图制作一个装饰器,告诉我我的函数需要多长时间才能完成,但显然当我尝试在一个应该返回某些内容的函数上使用它时,它只返回“None”

我只看到了几个关于这个问题的问题,但没有一个真正有帮助

这是我的代码

import time


def time_it(func):  # Here i make a simple decorator function that should time my decorated function
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args)
        t2 = time.time()
        total = t2 - t1
        print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")

    return wrapper


@time_it
def square(nums):  # I make a function that squares every number in a list
    new_list = []
    for n in nums:
        new_list.append(n ** 2)
    return new_list


lis = [f for f in range(200000)]  # i make a list with a range of 200000
print(square(lis))  

抱歉有任何语法错误,我不是以英语为母语的人

【问题讨论】:

  • 是的,因为wrapper 总是返回None

标签: python python-3.x decorator


【解决方案1】:

问题是您的内部函数返回值没有被返回。变化如下:

from functools import wraps

def time_it(func):  # Here i make a simple decorator function that should time my decorated function
    @wraps(func)
    def wrapper(*args, **kwargs):
        t1 = time.time()
        ## Note the change on this line -- I now store the return result from the called function 
        result = func(*args, **kwargs)
        t2 = time.time()
        total = t2 - t1
        print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")

        ## And then explicitly return the result
        return result

    return wrapper

对于装饰器,你需要记住它只是一个闭包,有一些花哨的语法。函数返回参数还是需要自己处理。

几个补充:

【讨论】:

  • 最好让 OP 使用所有参数,例如:result = func(*args, **kwargs) 以防万一...在这里也使用functools.wraps 也无妨...
  • 是的,你是对的。我更新了示例以反映这一点。谢谢!
【解决方案2】:

装饰器将square 替换为wrapper 并且wrapper 不返回任何内容。它应该返回包装函数返回的值。

这是正确的做法:

def time_it(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        try:
            return func(*args, **kwargs)
        finally:
            t2 = time.time()
            total = t2 - t1
            print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")

    return wrapper

我改变了 3 件事:

  • 添加return,以便从修饰函数返回值
  • **kwargs 添加到func 调用,因为如果使用不同,可能需要它
  • 添加了try/finally 块,这样即使在出现异常的情况下也会发生打印输出,而且这使得返回值更容易。

【讨论】:

    【解决方案3】:

    您的装饰函数不会显式返回任何内容 - 因此,默认情况下,它会返回 None

    您可以在打印时间之前捕获输出,并在最后返回:

    def time_it(func):  # Here i make a simple decorator function that should time my decorated function
        def wrapper(*args, **kwargs):
            t1 = time.time()
            out = func(*args)
            t2 = time.time()
            total = t2 - t1
            print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")
            return out
        return wrapper
    

    【讨论】:

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