Python Decorators Explained For Beginners
In the world of Python programming, decorators can be an elegant and powerful tool in the hands of experienced developers.
Decorators give you the ability to modify the behavior of functions without altering their source code, providing a concise and flexible way to enhance and extend their functionality.
In this article, I'll go over the intricacies of how to use decorators in Python, and show examples of where they are useful.
Quick Function Recap
Simply put, a function is a way of running a block of code repeatedly with different arguments.
In other words, it can take inputs, use those inputs to run some pre-defined set of code, and then return an output.
Functions take in inputs, use it to run a set of code and returns an output
In Python, a function is written like so:
def add_one(num):
return num + 1
When we want to call it, we can write the function's names with parenthesis and pass in the necessary inputs (arguments):
final_value = add_one(1)
print(final_value) # 2
Note that for the most part, arguments and parameters mean the same thing. They are the variables used in the function.
The difference lies in where we are referring to them. Arguments are what we pass into the function when calling it, and parameters are what is declared in the function.
How to Pass Functions as Arguments
Commonly, when calling functions with arguments, we pass values such as Integers, Floats, Strings, Lists, Dictionaries and other data types.
But, something we can also do is to pass a function as an argument as well:
def inner_function():
print("inner_function is called")
def outer_function(func):
print("outer_function is called")
func()
outer_function(inner_function)
# outer_function is called
# inner_function is called
In this example we create two functions: inner_function
and outer_function
.
outer_function
has a parameter called func
which it calls after it itself is called.
outer_function executes first. It then calls the function that was passed as a parameter
Think about it like how we can treat functions like any other value or variable.
The proper term for this is that functions are first class citizens. This means that they are just like any other object and can be passed as arguments into other functions, be assigned to variables, or returned by other functions.
So, outer_function
can take in a function as a parameter and call it when it is executed.
How to Return Functions
Another benefit of being able to treat functions as objects is that we can define them in other functions and return them as well:
def outer_function():
print("outer_function is called")
def inner_function():
print("inner_function is called")
return inner_function
Note that in this example, when we return inner_function
, we didn't call it.
We only returned the reference to it, so that we can store and call it later on:
returned_function = outer_function()
# outer_funciton is called
returned_function()
# inner_function is called
If you are like I am, this might seem interesting and all, but you are still probably wondering how this can be useful in actual programs 🤔. This is something we'll take a look at in a moment!
How to Create Decorators in Python
Accepting functions as arguments, defining functions within other functions, and returning them are exactly what we need to know to create decorators in Python. We use decorators to add additional functionality to existing functions.
For example, if we wanted to create a decorator that will add 1 to the return value of any function, we can do it like so:
def add_one_decorator(func):
def add_one():
value = func()
return value + 1
return add_one
Now, if we have a function that returns a number, we can use this decorator to add 1 to whatever value it outputs.
def example_function():
return 1
final_value = add_one_decorator(example_function)
print(final_value()) # 2
In this example, we call the add_one_decorator
function and pass in the reference to example_function
.
When we call the add_one_decorator
function, it creates a new function, add_one
, defined within it and returns a reference to this new function. We store this function in the variable final_value
.
So, when executing the final_value
function, the add_one
function is called.
The add_one
function defined within add_one_decorator
will then call example_function
, store its value, and add one to it.
Ultimately, this results in 2
being returned and printed to the console.
Process of how the code will execute
Notice how we didn't have to change the original example_function
to modify its return value and to add functionality to it. This is what makes decorators so useful!
Just to clarify, decorators aren't specific to Python. They're a concept that can be applied in other programming languages. But in Python, you can make use of them easily using the @
syntax.