Definition: allow the user the add new functionality to the existent object without changing its structure.
Example 1: create a basic decorator
def decorator(f):
# modify the f
def wrapper():
result = f() # string
upper_result = result.upper()
return upper_result
return wrapper
@decorator
def say_hi():
return 'hello there'
a = say_hi()
b = decorator(say_hi)() # function as the input variable
print(a)
print(b)
Example 2:
decorator without paramter
function variable with parameter
def prepost(f):
def wrapper(*args, **kwargs):
print(" start")
result = f(*args, **kwargs)
print(" end")
return result
return wrapper
@prepost
def multiplication(x, y):
print('middle')
return x * y
print(multiplication(3, 4))
Example 3:
decorator with parameter;
function variable without parameter
def decorator(*dargs, **dkwargs):
print("Step 1")
def wrapper(f): # function variable is here
print("Step 3")
print("I like", dkwargs['like'])
result = f()
return result
print("Step 2")
return wrapper
@decorator(like = "geeksforgeeks")
def my_func():
print("Step 4")
Example 4:
decorator with parameters
function variable with parameters
def decorator(*dargs, **dkwargs):
print("Step 1")
def inner(f):
print("Step 3")
def wrapper(*fargs, **fkwargs):
print("Step 5")
print("sum of decorator paramters {}".format(dkwargs['x']+dkwargs['y']) )
result = f(*fargs, **fkwargs)
return result
print("Step 4")
return wrapper
print("Step 2")
return inner
@decorator(x=1, y=2)
def my_fun(*args):
print("Step 6")
for ele in args:
print(ele)
# another way of using dacorators
my_fun('a', 'b', 'c')
Example 5:
multiple decorators without parameters
implemented by functools
from functools import wraps
def makebold(fn):
@wraps(fn)
def wrapped(*args, **kwargs):
return "<b>" + fn(*args, **kwargs) + "</b>"
return wrapped
def makeitalic(fn):
@wraps(fn)
def wrapped(*args, **kwargs):
return "<i>" + fn(*args, **kwargs) + "</i>"
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
@makebold
@makeitalic
def log(s):
return s
print(hello()) # returns "<b><i>hello world</i></b>"
print(hello.__name__) # with functools.wraps() this returns "hello"
print(log('hello')) # returns "<b><i>hello</i></b>"
Example 6: decorator with optional parameters (both decorators need parenthesis)
from functools import wraps
def decorator(colour=None):
def inner(func):
colour_open = ('<span style="color: {};">'.format(colour)
if colour else '')
colour_close = '</span>' if colour else ''
def wrapper(*args, **kwargs):
return ('{colour_open}<b>{message}</b>{colour_close}'
.format(colour_open=colour_open,
colour_close=colour_close,
message=func(*args, **kwargs)))
return wrapper
return inner
@decorator()
def say_hello(user):
return 'hello, {}'.format(user)
@decorator(colour='red')
def say_bye(user):
return 'See you, {}'.format(user)
print(say_hello("good"))
print(say_bye("good"))
Example 7: decorator with and without parenthesis
# func != None: @decorator
# func = None: @decorator()
def decorator(func=None, prefix=None):
def inner(f):
def wrapper(*a, **ka):
if prefix:
print(f"{prefix} start")
result = f(*a, **ka)
if prefix:
print(f"{prefix} end")
return wrapper
if callable(func):
return inner(func) # 2 levels
else:
return inner # 3 levels
@decorator(prefix="outer")
def say_good():
print("bye")
@decorator()
def say_hi():
print("hello")
@decorator
def say_bye():
print("bye")
say_good()
say_hi()
say_bye()