2017-04-15 118 views
0

我已经做了两个功能做同样的事情,但不同。我想比较每个函数运行的时间,所以我添加了一个装饰器@calcul_time。该脚本确实工作,但我得到以下错误信息:Python装饰器离开NoneType错误

{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

Euh这不是一个装饰者如何工作... –

+0

'calcul_time'永远不会返回任何东西,因此'NoneType'错误,因为没有返回的方法总是返回'None'。装饰者应该返回一个可调用的 –

回答

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参数(将被传递给装饰器,你可以依靠它作为一个封闭),和返回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确保print()无论是在fonction会发生什么执行。