xxxxxxxxxx
### Decorators: Decorators are nothing but nested functions, where the parent function
### takes only a function as input and the child function modifies the behavior of input function
import time
from functools import wraps
def decorator(func):
"""A decorator that prints how long a function took to run."""
# Use @wraps to bind function's meta data like docstring / function name etc
@wraps(func)
# Define the wrapper function to return.
def changed_func(*args, **kwargs):
t_start = time.time()
# Call the decorated function and store the result.
result = func(*args, **kwargs)
t_total = time.time() - t_start
print('{} took {}s'.format(func.__name__, t_total))
return result
return changed_func
@decorator
def sleep_n_seconds(n):
time.sleep(n)
sleep_n_seconds(5) # 5.00001
########################
### Decorator Factory: An outermost function that wraps around a decorator and takes argument for
### the decorator since the decorator itself cannot take any argument other than a single function
from functools import wraps
# an outer function that takes argument
def decorator_factory(n):
"""Define and return a decorator"""
def decorator(func):
@wraps(func)
def changed_func(*args, **kwargs):
for i in range(n):
func(*args, **kwargs)
return changed_func
return decorator
run_three_times = decorator_factory(3)
@run_three_times
def print_sum(a, b):
print(a + b)
@decorator_factory(3)
def print_sum(a, b):
print(a + b)
xxxxxxxxxx
def our_decorator(func):
def function_wrapper(x):
print("Before calling " + func.__name__)
func(x)
print("After calling " + func.__name__)
return function_wrapper
@our_decorator
def foo(x):
print("Hi, foo has been called with " + str(x))
foo("Hi")
xxxxxxxxxx
def uppercase_decorator(func):
def function_wrapper(x):
print("Before calling " + func.__name__)
# function that is decorated making name parameter always uppercase
func(x.upper())
print("After calling " + func.__name__)
return function_wrapper
@uppercase_decorator
def user(name):
print(f"Hi, {name}")
user("Sam")
# output
# Before calling user
# Hi, SAM
# After calling user
xxxxxxxxxx
from functools import wraps
def debug(func):
@wraps(func)
def out(*args, **kwargs):
print('hello world')
return func(*args, **kwargs)
return out
@debug
def add(x, y):
return x + y
xxxxxxxxxx
# Decorator with arguments
import functools
# First function takes the wanted number of repetition
def repeat(num_times):
# Second function takes the function
def decorator_repeat(func):
# Third function, the wrapper executes the function the number of times wanted
# functools decorator to print the true name of the function passed instead of "wrapper"
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(num_times):
result= func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
# Our function using the decorator
@repeat(num_times= 3)
def greet(name):
print(f"Hello {name}")
greet("thomas")
xxxxxxxxxx
def deco(function):
def wrap(num):
if num % 2 == 0:
print(num,"is even ")
else:
print(num,"is odd")
function(num)
return wrap
@deco
def display(num):
return num
display(9) # pass any number to check whether number is even or odd
xxxxxxxxxx
# this functon converts any string into uppercase
def deco(function):
def wrap(s):
return s.upper()
function(s)
return wrap
@deco
def display(s):
return s
print(display("not bad"))
xxxxxxxxxx
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
xxxxxxxxxx
>>> from functools import wraps
>>> def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print('Calling decorated function')
return f(*args, **kwds)
return wrapper
>>> @my_decorator
def example():
"""Docstring"""
print('Called example function')
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
xxxxxxxxxx
# decorator function to convert to lowercase
def lowercase_decorator(function):
def wrapper():
func = function()
string_lowercase = func.lower()
return string_lowercase
return wrapper
# decorator function to split words
def splitter_decorator(function):
def wrapper():
func = function()
string_split = func.split()
return string_split
return wrapper
@splitter_decorator # this is executed next
@lowercase_decorator # this is executed first
def hello():
return 'Hello World'
hello() # output => [ 'hello' , 'world' ]