2017-04-15 60 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會發生什麼執行。