# What is decorators in python Decorators are used to add functionalities to an object without changing the structure of the object ## Let's see how a function looks like ```python= def add_one(no): return no + 1 num = add_one num(5) ``` > Output: 6 ## Let's see an example of Inner/nested function 🤔 ```python= def add_one(no): def add_two(no): return no + 2 return add_two(no) print(add_one(4)) ``` > Output: 6 ## Let's see what will happen if we pass function as a parameter to a different function ```python= def add_one(number): return number + 1 def fun(function): to_add = 5 return function(to_add) print(fun(add_one)) ``` > Output: 6 we have created two function where `fun` can have function as parameter and we are passing `add_one` as a function parameter to `fun` function then we are passing the `to_add` value to the `add_one` function Now you're getting, how we are going to get to decorators. ## We can also return functions from functions ```python= def parent(num): def first_child(): return "It's Itachi" def second_child(): return "I'm Sasuke" if num == 1: print(first_child()) return first_child else: print(second_child()) return second_child first = parent(1) second = parent(2) print(first) print(second) ``` > It's Itachi > I'm Sasuke > <function parent.<locals>.first_child at 0x7f6e5c7ff820> > <function parent.<locals>.second_child at 0x7f6e5c7ff940> ```python= first() #>>> It's Itachi second() #>>> I'm Sasuke ``` Note: we are returning `first_child` without parentheses. this means we are returning a reference to the function `first_child`. Where `first_child()` with parentheses returns the result of the function. Python also allows to use functions as return values. > ### **This is why functions are called First-Class Objects** functions can be passed around and used as arguments, just like any other object (str, int, bool, list, etc). ## What is `Closure` not closer from chainsmokers 😅 ```python= def print_message(message): "Outer Function" def send_message(): "Nested Function" print(message) send_message() print_message("Some message") ``` > Output: Some message # @Decorators First using normal function ```python= def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper def hello(): return "Hey there" decorate = uppercase_decorator(hello) print(decorate()) ``` > Output: HEY THERE Now same thing using decorator ```python= def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper @uppercase_decorator def hello(): return "using decorator" print(hello()) ``` > Output: USING DECORATOR To debug decorators we can use functools ```python= import functools def uppercase_decorator(func): @functools.wraps(func) def wrapper(): return func().upper() return wrapper @uppercase_decorator def say_hi(): "This will say hi" return 'hello there' print(say_hi()) print(say_hi.__name__) print(say_hi.__doc__) ``` > Output: HELLO THERE > say_hi > This will say hi ###### tags: `python` `decorators` `interview`