Python装饰器留下NoneType错误

时间:2017-04-15 12:09:06

标签: python decorator python-decorators

我做了两个函数做同样的事情,但不同。我想比较每个函数运行的时间,所以我添加了一个装饰器@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()

1 个答案:

答案 0 :(得分:3)

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

你的装饰师什么都不返回:

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参数(将传递给装饰器,您可以依赖它作为闭包),并返回{ {1}}。现在装饰器返回一个替换。

您可能希望使它更通用一些,并使用wrapper*args传递任意参数,并处理返回值(将其传递给{{1}的调用者})和例外正确。

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

**kwargs

wrapper()确保执行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中发生了什么。