Python - Decorators
@decorator syntax in Python? In Python, the @decorator syntax is used to apply a decorator to a function. Decorators are a way to extend or modify the behavior of functions without changing their actual code. The @decorator syntax provides a convenient and readable way to specify that a particular function should be wrapped or modified by a decorator function.
Here is the role of the @decorator syntax:
@decorator_function
def my_function():
# Function code
In this syntax:
-
@decorator_function: This line indicates that the functionmy_functionshould be decorated by thedecorator_function. -
def my_function():: This is the definition of the function that will be modified or extended by the decorator.
Here's an example to illustrate the role of the @decorator syntax:
# Decorator function
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
# Applying the decorator using @decorator syntax
@my_decorator
def say_hello():
print("Hello!")
# Using the decorated function
say_hello()
In this example, @my_decorator is applied above the say_hello function definition. This syntax is a shorthand for say_hello = my_decorator(say_hello). It indicates that the say_hello function should be decorated by the my_decorator function.
When you run this program, you will get the following output:
Something is happening before the function is called. Hello! Something is happening after the function is called.
In Python, higher-order functions are functions that can take other functions as arguments or return functions as results. Decorators leverage the concept of higher-order functions to modify or extend the behavior of functions. A decorator is essentially a higher-order function that takes a function as an argument and returns a new function.
Here's an example to illustrate the concept:
# Higher-order function (decorator)
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
# Function to be decorated
def say_hello():
print("Hello!")
# Applying the decorator using higher-order function
decorated_function = my_decorator(say_hello)
# Using the decorated function
decorated_function()
In this example:
-
my_decoratoris a higher-order function because it takessay_helloas an argument and returns a new functionwrapper. -
decorated_functionis the result of applying the decorator tosay_hello.
When you run this program, you will get the following output:
Something is happening before the function is called. Hello! Something is happening after the function is called.
Now, let's see how decorators and higher-order functions can be used with the @decorator syntax:
# Decorator function (higher-order function)
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
# Applying the decorator using @decorator syntax
@my_decorator
def say_hello():
print("Hello!")
# Using the decorated function
say_hello()
In this case, @my_decorator is a shorthand for say_hello = my_decorator(say_hello), illustrating how the @decorator syntax is another way to work with higher-order functions and decorators in Python.
When you run this program, you will get the following output:
Something is happening before the function is called. Hello! Something is happening after the function is called.
In Python, you can create a decorator that takes arguments by defining a higher-order function where the decorator function itself takes parameters. This allows you to customize the behavior of the decorator based on the arguments provided. The syntax involves having a function that returns the actual decorator.
Here's an example of creating a decorator with arguments:
# Decorator function with arguments
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
# Applying the decorator with arguments
@repeat(times=3)
def say_hello():
print("Hello!")
# Using the decorated function
say_hello()
In this example:
-
repeatis a higher-order function that takes an argumenttimes. -
decoratoris the actual decorator function that takes another functionfuncas its argument. -
wrapperis the modified function that repeats the original functiontimesand prints a message.
When you run this program, you will get the following output:
Calling say_hello Hello! Calling say_hello Hello! Calling say_hello Hello!
You can customize the behavior of the decorator by providing different arguments when applying it to a function. In this example, @repeat(times=3) indicates that the say_hello function should be repeated three times.
In Python, you can apply multiple decorators to a single function by stacking them using the @decorator syntax. When multiple decorators are used, they are applied in the order from the innermost to the outermost, creating a chain of transformations on the original function.
Here's an example to illustrate the use of multiple decorators:
# First decorator
def decorator1(func):
def wrapper():
print("Decorator 1 - Before function is called.")
func()
print("Decorator 1 - After function is called.")
return wrapper
# Second decorator
def decorator2(func):
def wrapper():
print("Decorator 2 - Before function is called.")
func()
print("Decorator 2 - After function is called.")
return wrapper
# Applying multiple decorators
@decorator1
@decorator2
def my_function():
print("Original function.")
# Using the decorated function
my_function()
In this example:
-
decorator1is the first decorator that adds behavior before and after the function call. -
decorator2is the second decorator that also adds behavior before and after the function call. -
@decorator1and@decorator2are applied tomy_functionin sequence.
When you run this program, you will get the following output:
Decorator 1 - Before function is called. Decorator 2 - Before function is called. Original function. Decorator 2 - After function is called. Decorator 1 - After function is called.
The decorators are applied in the order they are listed, creating a chain of transformations. In this case, decorator1 is the outermost decorator, followed by decorator2.