Reputation: 27
I have made two functions doing the same thing but differently. I want to compare the time each function takes to run so I have added a decorator @calcul_time. The script does work but i get the following error message:
{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
I don't understand why I have this NoneType error message. If I comment my decorator, I don't have any errors. Hereunder my script. Does anyone know why I get this 'NoneType' error?
#!/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()
Upvotes: 0
Views: 1303
Reputation: 1122282
You haven't really built a decorator. A decorator has to return a the original function or a suitable replacement.
Your decorator returns nothing:
def calcul_time(fonction):
avant = time.time()
fonction()
apres = time.time()
print(apres - avant)
A decorator typically returns a wrapper function. You created the wrapper function, but not the decorator that returns it.
This would be a proper decorator:
def calcul_time(fonction):
def wrapper():
avant = time.time()
fonction()
apres = time.time()
print(apres - avant)
return wrapper
I renamed your calcul_time
wrapper to wrapper
, removed the fonction
argument (that would be passed to the decorator, you can rely on it as a closure), and returned the wrapper
. Now the decorator returns a replacement.
You probably want to make it a little more generic, and pass through arbitrary arguments with *args
and **kwargs
, and handle both the return value (pass it through to the caller of wrapper()
) and exceptions correctly.
You also want to use the @functools.wraps()
decorator to copy things like the name and attributes from the wrapped function to the 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
The try..finally
ensures that print()
is executed regardless of what happens in fonction
.
Upvotes: 3