A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.
Before we learn decorators, we must understand how Python treats functions.
1. Functions as First-Class Objects
In Python, functions are first-class objects. This means that functions can be passed around and used as arguments, just like any other object (string, int, float, list, and so on).
def say_hello(name):
return f"Hello {name}"
def greet_bob(greeter_func):
return greeter_func("Bob")
print(greet_bob(say_hello)) # Hello Bob
2. Nested Functions
We can define functions inside other functions.
def parent():
print("Printing from the parent() function")
def first_child():
print("Printing from the first_child() function")
def second_child():
print("Printing from the second_child() function")
second_child()
first_child()
parent()
Furthermore, a function can return another function.
3. Simple Decorator Syntax (@)
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
def say_whee():
print("Whee!")
say_whee = my_decorator(say_whee)
say_whee()
The @ Syntax (Syntactic Sugar)
Instead of writing say_whee = my_decorator(say_whee), Python allows you to use decorators in a simpler way with the @ symbol.
def my_decorator(func):
def wrapper():
print("Before execution")
func()
print("After execution")
return wrapper
@my_decorator
def say_whee():
print("Whee!")
say_whee()
4. Decorator with Arguments
What if the function we want to decorate takes arguments? We need to use *args and **kwargs in the inner wrapper function.
def do_twice(func):
def wrapper_do_twice(*args, **kwargs):
func(*args, **kwargs)
func(*args, **kwargs)
return wrapper_do_twice
@do_twice
def greet(name):
print(f"Hello {name}")
greet("World")
Output:
Hello World
Hello World
5. Chaining Decorators
You can apply multiple decorators to a single function by stacking them. The decorators are applied from bottom to top.
def make_bold(func):
def wrapper():
return "<b>" + func() + "</b>"
return wrapper
def make_italic(func):
def wrapper():
return "<i>" + func() + "</i>"
return wrapper
@make_bold
@make_italic
def hello():
return "Hello World"
print(hello()) # <b><i>Hello World</i></b>
Discussion
Loading comments...