Course Content
Mastering Python: Closures and Decorators
Mastering Python: Closures and Decorators
What are Decorators?
Let's discuss decorators.
Note that "Decorators" can be a challenging topic for beginners. We will examine decorators in detail, step by step, explaining how they work, but it may be challenging to comprehend. Are you prepared for the challenges? That's why you're here!
Note
The prerequisite topic for understanding decorators is closure. Therefore, make sure you understand how closure works before diving into decorators.
Decorators
Decorators are functions that add extra functionality to another function using the closure.
Code Description
decorator(func)
function:
- This function takes another function wrapper(argument1, argument2)
function:
- This is the wrapper function created inside the add(a, b)
function:
- This is the original function that we want to enhance with the decorator.add = decorator(add)
:
- Here, we use the - Function calls and output: - Now that the decorator is applied to the
func
as an argument. The purpose of this function is to create and return a new function (a wrapper) that will execute some additional code before and after calling func
.decorator()
function. It takes two arguments, argument1
and argument2
.- The
wrapper()
function starts by printing "Function starts executing" to indicate the beginning of the function's execution.- It then calls the original function
func(argument1, argument2)
, where func
is the function passed as an argument to the decorator()
.- After calling
func
, it prints "Function ends executing" to indicate the end of the function's execution.- The result of
func(argument1, argument2)
is stored in the variable result
.- Finally, it returns the
result
.- It takes two arguments,
a
and b
.- It prints the message with the sum of
a
and b
and returns their sum.decorator()
function to enhance the behavior of the add()
function.- By assigning
add = decorator(add)
, we replace the original add()
function with the new version of add()
that has the decorator applied to it. Now, whenever we call add()
, we are actually calling the wrapper()
function from the decorator.add()
function, whenever we call add(a, b)
, it actually calls the wrapper()
function instead.- The
wrapper()
function executes the additional code before and after calling the original add()
function.- The output shows the messages from the
wrapper()
function and the result of the original add()
function.As you can see, the decorator successfully wraps the
add()
function, allowing us to add custom behavior to it without modifying its original code. Decorators are powerful tools in Python, used to add functionality, logging, or other cross-cutting concerns to functions or methods in a clean and reusable way.
Here is an example of how a decorator works. The decorator()
function takes a function as an argument, defines the wrapper()
function, encloses the taken function within the wrapper()
, and returns the wrapper()
. There are three steps to the decorator's work:
- Taking a function as an argument.
- Enclosing the function within the newly defined function (
wrapper
). - Returning the
wrapper
function with the enclosed function.
The wrapper()
function contains the main decorator logic and invokes the function with the given parameters.
The add()
function is reassigned by the returned wrapper()
function that now contains the enclosed add()
function.
Decorator Implementing
Step 1. Define the decorator.
The decorator should take exactly one argument.
Step 2. Define the inner function.
We need to define the inner function to close the function taken by decorator()
.
Step 3. Enclose the taken function.
The function should be called inside the inner function (wrapper
), and the result should be saved and returned.
Step 4. Return the inner function.
The decorator should return the inner function wrapper
without calling.
How does the decorator work?
Step 1: Decorator is called.
The decorator()
function is called and takes the function (decorated function) as the argument func
. At this step, the interpreter creates the decorator()
local scope.
Step 2: Define the wrapper function.
The interpreter defines the wrapper()
function (in the decorator()
local scope) that takes the same arguments as the decorated function. The wrapper()
body contains the main logic of the decorator and calls the function from the non-local scope.
The wrapper()
function is not executed at this step.
Step 3: Decorator execution ends.
The decorator()
function ends the execution and returns the wrapper()
function. The interpreter removes the decorator()
local scope but leaves the enclosed objects.
Step 4: Reassignment
The returned wrapper()
function assigns to the decorated function: The decorated function is replaced by the other function (wrapper()
), and the previously contained function is removed.
The previous add()
function is removed but enclosed inside the returned wrapper()
function.
Step 5: Usage
The new function is the returned wrapper()
function that takes arguments and inserts them into the enclosed function.
Note
The
add
is a variable that contains a reference to the function that we defined.
Everything was clear?