Python decorators are incredible useful for extending functions with other functionality.
import functools
is required for each of these decorators.
Write results to file
def write_result_to_file(file, mode='w', encoding='utf-8', encoding_opts=[]):
def decorator_write_result_to_file(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
with open(file, mode) as f:
if 'b' in mode and isinstance(result, str):
result = result.encode(encoding, *encoding_opts)
f.write(result)
return result
return wrapper
return decorator_write_result_to_file
Appending to a file the result of a function call
@write_result_to_file('test.txt', mode='a')
def do_something:
return 42
a = do_something() # test.txt and a contain 42
Printing a functions run time
import time
def timer(func):
"""Print the runtime of the decorated function"""
@functools.wraps(func)
def wrapper_timer(*args, **kwargs):
start_time = time.perf_counter() # 1
value = func(*args, **kwargs)
end_time = time.perf_counter() # 2
run_time = end_time - start_time # 3
print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
return value
return wrapper_timer
Capturing some debug info
def debug(func):
"""Print the function signature and return value"""
@functools.wraps(func)
def wrapper_debug(*args, **kwargs):
args_repr = [repr(a) for a in args] # 1
kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()] # 2
signature = ", ".join(args_repr + kwargs_repr) # 3
print(f"Calling {func.__name__}({signature})")
value = func(*args, **kwargs)
print(f"{func.__name__!r} returned {value!r}") # 4
return value
return wrapper_debug
Execute something after sleeping
def slow_down(seconds=1):
"""Sleep n seconds (or 1 second) before calling the function"""
def decorator_slow_down(func):
@functools.wraps(func)
def wrapper_slow_down(*args, **kwargs):
time.sleep(seconds)
return func(*args, **kwargs)
return decorator_slow_down
return wrapper_slow_down
Execute multiple times
def repeat(num_times):
def decorator_repeat(func):
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
for _ in range(num_times):
value = func(*args, **kwargs)
return value
return wrapper_repeat
return decorator_repeat