Before you can understand decorators, you must first understand how Functions work.
Decorators to add functionality to an existing code(Functions\Methods)
It allows programmers to modify the behavior of existing function or class
@decorator def func_name(): ''' Function implementation'''
is equivalent to
#Normal Function def func_name(): ''' Function implementation''' func_name = decorated_function(func_name)
Basically, a decorator takes in a function, add\modify some functionality and returns it.
#decorator function def make_pretty(func): def inner(): print("I got decorated") func() return inner #normal function def ordinary(): print("I am ordinary") #decorator call pretty = make_pretty(ordinary) pretty()
#decorator function def make_pretty(func): def inner(): print("I got decorated") func() return inner @make_pretty def ordinary(): print("I am ordinary") #decorator call ordinary()
I am ordinary I got decorated I am ordinary
In the both above methods make_pretty() is a decorator.
In the line pretty = make_pretty(ordinary), The function ordinary() got decorated and the returned function was given the name pretty and call the decorated function by pretty()
and we can see in the output, the decorator function added some new functionality to the original function. The decorator acts as a wrapper for the function ordinary.
So, @my_decorator is just an easier way of saying method 1. It’s how you apply a decorator to a function.
@decorator(params) def func_name(): ''' Function implementation'''
is equivalent to
def func_name(): ''' Function implementation''' func_name = (decorator(params))(func_name)
def smart_add_two_number(func): def inner(a, b): if type(a) == str or type(b) == str: print("OOPS!!! We can't add String Object") return return func(a, b) return inner @smart_add_two_number def add_two_number(a, b): print(a+b) add_two_number(2,10) #Output: 12 add_two_number(2,"K") #Output: OOPS!!! We can't add String Object
You might notice that parameters of the nested inner() function inside the decorator is the same as the parameters of functions it decorates. Taking this into account, now we can make general decorators that work with any number of parameters.
In Python, this magic is done by *args & **kwargs. In this way, args will be the tuple of positional arguments and kwargs will be the dictionary of keyword arguments. An example of such a decorator will be:
def works_for_all_functions(func): def inner(*args, **kwargs): print("I can decorate any function") return func(*args, **kwargs) return inner
If you have any doubts or queries related to this chapter, get them clarified from our Python Team experts on ibmmainframer Community!