- Implement a Decorator: Functions as First-Class Objects
- Implement a Parameterized Decorator in Python
Implement Decorator Using
- Implement Multiple Decorators in Python
One of Python’s most predominant features is that we can use decorators to change the behavior of functions or classes. We can use decorators to make changes in a part of the program with codes already inside the program.
Decorators are lines of code in a program that change some part of that program during execution. The process of eliciting changes to a program during compilation is called metaprogramming.
In this article, the reader will go through the basics of decorators, i.e., how it is declared, implemented, and chained together in Python.
Implement a Decorator: Functions as First-Class Objects
Syntactically, we can declare decorators by passing a function as an iterable object to another. This is possible because everything in Python is a first-class object; thus, we can pass every Python construct as a parameter or assign it to a variable.
That means every class, function, and declared variable could be passed as objects. The below examples demonstrate this:
def func(): def inner(): print("Chocolate") return inner taste = func() taste()
"C:\Users\Win 10\main.py" Chocolate Process finished with exit code 0
Here, a nested function is created, where the parent function
func() has an inner function
inner() function prints a statement and returns itself while inside a function.
The decorator function
func() passes its data to an empty object function
taste. Thus decorating it.
If this object function had any functionality, the decorator would have made changes to it as well. In the latter parts of this article, you will see how decorators are used for eliciting change to a function.
In Python, we can pass and return functions as arguments to other functions. A decorator can also accept a function as an argument and return results using this notion.
The example below demonstrates parameterized decorators. To understand it more easily, think of functions as real-world objects.
Implement a Parameterized Decorator in Python
We will present a bakery example to understand how decorators can take other functions as parameterized arguments.
bakery is a parameterized method that takes an object function
obj_func() as a parameter. Inside this method, a nested function
inner() is declared, which prints
obj_func() is called, returning the
inner() function. Calling the object function calls the function that is being decorated.
As you can closely observe, the
bakery is a parameterized method that takes the argument
obj_func(), which is nothing but the function
wheat(), and calls it after the
inner() function executes the
def inner(): print("Dough") obj_func() return inner
This function which ought to be decorated, i.e.,
wheat, has a
Turned into bread.
def wheat(): print("Turned into bread")
A new object function
final is created that stores the decorated function.
object_function = decorator(decorated_function) decorates the function
wheat() by passing it as an object to the parameterized method
bakery, which implements the properties of the
inner() function to it.
final = bakery(wheat) final()
The decorated function is saved in the object function
final. When compiled, the program executes the
inner() function first, then calls
obj_func(), which passes the object function
wheat() and prints its contents.
Loosely put, wheat is converted into bread when placed inside a bakery, and the result is printed:
Turned into bread. Just like how a bakery works in the real world!
def bakery(obj_func): def inner(): print("Dough") obj_func() return inner def wheat(): print("Turned into bread") final = bakery(wheat) final()
"C:\Users\Win 10\main.py" Dough Turned into bread Process finished with exit code 0
Implement Decorator Using
@ in Python
This segment demonstrates how a function can be decorated using the syntax
@function_name. In this example, a program is used which has:
- A parameterized nested function;
- An inner function that checks the values between variables x and y and swaps them if the numerator is smaller than the denominator;
- A third function that gets decorated with the swapped values divides the two numbers and prints them.
The decorator function
decor_func takes in an object function
obj1 as its parameter. Inside, the inner function is created that swaps values if a larger number is provided in the denominator field.
def decor_func(obj1): def swap(x, y): pass
As the inner function
swap parameters are the same as the function
quot parameters, the swapped values stored inside
obj1 are returned from the inner function, passing the changed values to the function
quot before the compiler executes it.
@decor_func is declared above the function
quot in the example. It tells the compiler to take the parameters of function
obj1 and pass them to the function
def decor_func(obj1): def swap(x, y): if x < y: temp = x x = x + y - x y = y + temp - y return obj1(x, y) return swap # Syntax to Decorate function @decor_func def quot(x, y): # Displays quotient of variable x/y print(x / y) quot(2, 4)
"C:\Users\Win 10\main.py" 2.0 Process finished with exit code 0
Implement Multiple Decorators in Python
Chaining decorators is a technique to stack decorators on top of one another so that the target function gets decorated repeatedly, for the number of times
@function_name is declared.
In the below program, two functions are created,
decor1. These functions are decorators and have an inner function, which performs arithmetic operations and returns the result.
To chain decorators, these must be defined together (on top of each other) above the function to be decorated. It must also be noted that the compiler reads decorators from bottom to top.
This means the decorator placed just above the function name gets implemented first, and the other decorators are implemented after that toward the top.
@decor # Gets implemented second @decor1 # Gets implemented first def num(): return 5
In the below example, the function
num() returns a value to the decorator functions serially. At first,
decor1 takes the value, passes it to the object function
func(), and returns the altered value to
Similarly, this process is repeated with the other decorator function. Finally, when
num() is printed, it produces
50 as the output.
# code for testing decorator chaining def decor1(func): def inner(): x = func() return x * x return inner def decor(func): def inner(): x = func() return 2 * x return inner @decor @decor1 def num(): return 5 print(num())
"C:\Users\Win 10\main.py" 50 Process finished with exit code 0
This article provided a clear picture to the reader of how decorators are used in a program. The reader should learn how decorators can be used for a function, how parameters can be provided to a decorator, and how to chain multiple decorators.