【问题标题】:Python decorator leaving NoneType errorPython 装饰器留下 NoneType 错误
【发布时间】:2017-04-15 12:09:05
【问题描述】:

我已经让两个函数做同样的事情但不同。我想比较每个函数的运行时间,所以我添加了一个装饰器@calcul_time。该脚本确实有效,但我收到以下错误消息:

{1: 1, 2: 3, 3: 2, 4: 4, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 2, 11: 2, 12: 2, 13: 2, 14: 2, 15: 2, 16: 2, 17: 2, 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 0, 24: 0}
0.0021219253540039062
{1: 1, 2: 3, 3: 2, 4: 4, 5: 4, 6: 3, 7: 3, 8: 2, 9: 2, 10: 2, 11: 2, 12: 2, 13: 2, 14: 2, 15: 2, 16: 2, 17: 2, 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 0, 24: 0}
8.702278137207031e-05
Traceback (most recent call last):
  File "./03_PeakHours.py", line 51, in <module>
    horaires1()
TypeError: 'NoneType' object is not callable

我不明白为什么我会收到此 NoneType 错误消息。如果我评论我的装饰器,我没有任何错误。下面是我的脚本。有谁知道为什么我会收到此“NoneType”错误?

#!/usr/local/bin/python3.5

import time

input='''5
1 8
2 3
4 23
4 6
2 23'''


def calcul_time(fonction):
    avant = time.time()
    fonction()
    apres = time.time()
    print(apres - avant)    


#@calcul_time
def horaires1():
    hours = {}
    for time in range(1,25):
        hours[time] = 0

    def inBetween(line):
        current = int(line.split(" ")[0])
        while current < int(line.split(" ")[1]):
            hours[current] +=1
            current += 1
    list(map(inBetween, input.split("\n")[1:]))
    print(hours)
    return 0


#@calcul_time
def horaires2():
    lines = input.split("\n")
    hours={}
    for time in range(1,25):
        hours[time] = 0

    for i in range(1, int(lines[0])+1):
        start, stop = lines[i].split(" ")
        for heure in range(int(start), int(stop)):
            hours[heure] += 1
    print(hours)
    return 0


horaires1()
horaires2()

【问题讨论】:

  • 呃,装饰器不是这样工作的......
  • calcul_time 从不返回任何东西,因此 NoneType 错误,因为没有返回的方法总是返回 None。装饰器应该返回一个可调用的

标签: python decorator python-decorators


【解决方案1】:

你还没有真正构建一个装饰器。装饰器必须返回一个原始函数或合适的替代函数

你的装饰器什么也不返回:

def calcul_time(fonction):
    avant = time.time()
    fonction()
    apres = time.time()
    print(apres - avant)    

装饰器通常返回一个包装函数。您创建了包装函数,但没有创建返回它的装饰器。

这将是一个合适的装饰器:

def calcul_time(fonction):
    def wrapper():
        avant = time.time()
        fonction()
        apres = time.time()
        print(apres - avant)    
    return wrapper

我将您的 calcul_time 包装器重命名为 wrapper,删除了 fonction 参数(将传递给装饰器,您可以依赖它作为闭包),并返回 wrapper。现在装饰器返回一个替换。

您可能希望使其更通用一点,并使用*args**kwargs 传递任意参数,并正确处理返回值(将其传递给wrapper() 的调用者)和异常。

您还想使用@functools.wraps() decorator 将名称和属性等内容从包装函数复制到包装器:

from functools import wraps

def calcul_time(fonction):
    @wraps(fonction)
    def wrapper(*args, **kwargs):
        avant = time.time()
        try:
            return fonction(*args, **kwargs)
        finally:
            apres = time.time()
            print(apres - avant)
    return wrapper

try..finally 确保无论fonction 中发生什么,都会执行print()

【讨论】:

    猜你喜欢
    • 2013-06-08
    • 1970-01-01
    • 2013-01-10
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 2016-06-13
    • 2021-11-22
    相关资源
    最近更新 更多