4
\$\begingroup\$

I am getting familiar with decorators, and after a couple of tutorials i came up with a decorator that might is useful for me. Is this the proper way to use decorators? Any suggestion about the code?

def timeit_decorator(original_function):
 import time
 import colorama
 def wrapper(*args, **kwargs):
 tm = time.time()
 res = original_function(*args, **kwargs)
 print("Function " + colorama.Fore.GREEN + original_function.__name__ + colorama.Style.RESET_ALL + " executed in " + colorama.Fore.GREEN + "~{:.2f}".format(
 (time.time() - tm) / 60) + colorama.Style.RESET_ALL + " minutes!")
 return res
 return wrapper

Example of usage:

@timeit_decorator
def display(msg):
 time.sleep(10)
 return msg
print(display(1))
asked Dec 15, 2016 at 11:44
\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

When using decorators, you should familiarize yourself with functools.wraps. Consider the difference in available informations between these two (useless) decorators:

from functools import wraps
def decorate1(func):
 def wrapper(*args, **kwargs):
 return func(*args, **kwargs)
 return wrapper
def decorate2(func):
 @wraps(func)
 def wrapper(*args, **kwargs):
 return func(*args, **kwargs)
 return wrapper

When applied to a function:

@decorate1
def test1(x, y, z):
 "test1 docstring"
 print(x, y, z)
@decorate2
def test2(x, y, z):
 "test2 docstring"
 print(x, y, z)

The help on each function look quite different:

>>> help(test1)
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
>>> help(test2)
Help on function test2 in module __main__:
test2(x, y, z)
 test2 docstring

Since you’re using Python 3, you should consider using better timing primitives. Namely time.perf_counter():

def wrapper(*args, **kwargs):
 begin = time.perf_counter()
 res = original_function(*args, **kwargs)
 elapsed = time.perf_counter() - begin

Lastly, you should consider using format all along instead of string concatenation:

import time
import colorama
from functools import wraps
def timeit_decorator(original_function):
 @wraps(original_function)
 def wrapper(*args, **kwargs):
 begin = time.perf_counter()
 result = original_function(*args, **kwargs)
 elapsed = time.perf_counter() - begin
 print("Function {color}{}{reset} executed in {color}"
 "~{:.2f}{reset} minutes!"
 .format(
 original_function.__name__,
 elapsed / 60,
 color=colorama.Fore.GREEN,
 reset=colorama.Style.RESET_ALL))
 return result
 return wrapper
answered Dec 15, 2016 at 12:55
\$\endgroup\$
1
  • \$\begingroup\$ Thanks a lot for the long answer, it was really helpful! \$\endgroup\$ Commented Dec 15, 2016 at 13:02

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.