Decorators
In Python, decorators are a powerful tool that allows you to modify or extend the behavior of functions or methods without changing their actual code. Essentially, a decorator is a function that takes another function as input and returns a new function that enhances or alters the original one in some way.
Basic Concept of Decorators
A decorator is typically defined as a function that accepts a function (or method) as an argument and returns a new function. The new function can modify the behavior of the original function, such as by adding extra functionality before or after calling the original function.
Basic Syntax:
def decorator_function(original_function):
def wrapper_function():
print("Wrapper executed this before {}".format(original_function.__name__))
return original_function()
return wrapper_function
You then apply the decorator to a function using the @
syntax:
@decorator_function
def display():
print("Display function executed")
# Running the decorated function
display()
Output:
Wrapper executed this before display
Display function executed
Explanation:
- The
@decorator_function
syntax is equivalent to writingdisplay = decorator_function(display)
. decorator_function
accepts the original function (display
) and returns a new function (wrapper_function
), which calls the original function inside it.- This allows the "wrapper" function to execute code before or after the original function call.
Example: Decorators with Arguments
A more advanced example is using decorators that accept arguments:
def decorator_with_args(prefix):
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print(f"{prefix}: {original_function.__name__} is being called")
return original_function(*args, **kwargs)
return wrapper_function
return decorator_function
@decorator_with_args("INFO")
def greet(name):
print(f"Hello {name}")
greet("John")
Output:
INFO: greet is being called
Hello John
Common Use Cases for Decorators:
- Logging: Tracking function calls or errors.
- Authorization: Checking user permissions before executing a function.
- Memoization/Caching: Storing results of expensive function calls.
- Timing: Measuring how long a function takes to execute.
Example: Timing Decorator
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time} seconds to execute")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(2)
print("Function completed!")
slow_function()
Output:
Function completed!
Function slow_function took 2.002347946167469 seconds to execute
Built-in Decorators
Python provides several built-in decorators, such as:
@staticmethod
: Declares a method as a static method.@classmethod
: Declares a method as a class method.@property
: Converts a method into a read-only property.
Decorators are versatile and can be used to add functionality to your code in a clean, reusable, and readable way.