# Example - 1
# Function Decorators
def start_and_end_1(func):
def wrapper():
print("Start")
func()
print("End")
return wrapper
def print_name():
print("Alex")
print_name = start_and_end_1(print_name)
print_name()
# Output
Start
Alex
End
# ----------------------------------------------------------------------------------
# Example - 2
# Function Arguments
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Start")
result = func(*args, **kwargs)
print(result)
print("End")
return result
return wrapper
@my_decorator
def add5(x):
return x + 5
add5(10)
# Ouput
Start
15
End
# ----------------------------------------------------------------------------------
# Example - 3
# Return values and function identity
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Do something before")
result = func(*args, **kwargs)
print(result)
print("Do something after")
return result
return wrapper
@my_decorator
def add_numbers(n1, n2):
return n1, n2
add_numbers(1, 2)
print('--------------------------------')
#Output
Do something before
(1, 2)
Do something after
# ----------------------------------------------------------------------------------
# Example - 4
# Decorator function arguments
import functools
def repeat(num_times):
def decorator_repeat(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=6)
def greet(name):
print(f"Hello {name}")
greet('Abhi')
print('--------------------------------')
#Output
Hello Abhi
Hello Abhi
Hello Abhi
Hello Abhi
Hello Abhi
Hello Abhi
# ----------------------------------------------------------------------------------
# Example - 5
# Nested Decorators
import functools
def start_end_decorator_2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Start")
result = func(*args, **kwargs)
print("End")
return result
return wrapper
def debug(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
args_repr = [repr(a) for a in args]
kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
signature = ", ".join(args_repr + kwargs_repr)
print(f"Calling {func.__name__}({signature})")
result = func(*args, **kwargs)
print(f"{func.__name__!r} returned {result!r}")
return result
return wrapper
@debug
@start_end_decorator_2
def say_hello(name):
greeting = f'Hello {name}'
print(greeting)
return greeting
say_hello("Alex")
print('--------------------------------')
#Output
Calling say_hello('Alex')
Start
Hello Alex
End
'say_hello' returned 'Hello Alex'
# ----------------------------------------------------------------------------------
# Example - 6
# Class decorators
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello")
say_hello()
say_hello()
say_hello()
#Output
Call 1 of 'say_hello'
Hello
Call 2 of 'say_hello'
Hello
Call 3 of 'say_hello'
Hello