Python decorators and internals explained for beginners — (part-1)

Chaitanya Volkaji
Mar 29 · 4 min read

In this article, we will deep dive into python decorators. We will discuss on what is the logic behind decorators, how to create them and how to use them in detail.

In simple words, a decorator is used to modify or extend the existing functionality with out modifying the original function.

Before diving into decorators, we need to understand some basics of first-class objects. In Python, functions are first-class objects. We can assign functions to variables, store in data structures, pass functions as arguments and return function as an output.

Assigning function to a variable

In the above example, we have defined hello function which accepts name as argument and prints the “hello name”. When we called the function hello(“chaitanya”), it prints “hello chaitanya”.

We assigned hello to greet variable and then called greet(“world”), it prints hello world. This is how we can assign functions to variables and work with variables as functions.

Next, we will learn about how we can pass function as an argument to a function.

Passing function as an argument

If we run above python script, we get below output.

In the above example, we have defined run and walk functions which prints some message. We have defined command function which accepts function as a parameter and then calls the function in the command function.

We have passed run function as an argument to command function. Command function took run function as an argument and called the run function inside the command function. This is how we can pass functions as arguments to functions.

Returning function as an output

If we run above python script, we get below output.

In the above example, we have defined a function named greet_function and inside greet_function we have defined a hello function and returned hello function. hello function takes name as an argument and prints hello name.

print(greet_function())

When we call greet_function(), we get hello function as a return value. We can see the value of print(greet_function()) as hello function in the output.

greet = greet_function()

We are assigning the hello function which is coming as a return value from greet_function() to greet variable. Now greet variable holds the hello function.

greet("chaitanya")

Now we will call greet(“chaitanya”) function will result in calling hello function.

Now, we will get into decorators concept.

We will write a simple decorator now.

If we execute the above script, we get below output.

We will go through above example in detail

def my_decorator(func):
def inner_function(name):
print("before calling function...")
func(name)
print("after calling function...")
return inner_function

We have defined my_decorator function which accepts function as an argument and we have defined one more function inner_function inside my_decorator function which accepts name as parameter and we are returning inner_function. In inner_function, we printed some message before and after calling the original function.

def say_hello(name):
print("Hello ",name)

We have defined function say_hello which accepts name as paramter and prints Hello name.

new_say_hello = my_decorator(say_hello)
print(new_say_hello)

We have passed say_hello function to my_decorator function and my_decorator function returns inner_function as a return value. We are assigning the same return value to new_say_hello. new_say_hello variable is holding inner_function.

Note : func in inner_function will hold say_hello function now.

when we print the new_say_hello variable, we can see it prints inner_function

new_say_hello("chaitanya")

Now when we call new_say_hello(“chaitanya”), inner_function gets called.

In inner_function,

print("before calling function...") #first prints this message
func(name) # calls say_hello function
print("after calling function...") # after calling say_hello function it prints this message

Now instead of variable name new_say_hello, I use the varible name same as original function

say_hello = my_decorator(say_hello)
print(say_hello)
say_hello("chaitanya")

Here we have decorated our say_hello function with my_decorator function and assigned to say_hello variable.

Now say_hello name gives us the feel like we are calling our say_hello function itself, but we are not doing that.

To simplify the syntax, we can also use @ symbol for decorating our original functions.

If we run above python script, we get following output.

@my_decorator
def say_hello(name):
print("Hello ",name)

is equivalent to

def say_hello(name):
print("Hello ",name)
say_hello = my_decorator(say_hello)

We will discuss more in next article.

I hope you understood the logic of how decorators work, please comment if anything is missing.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium