Decorators in Python are a powerful feature used to modify or extend functions or methods without changing their source code directly. They are functions themselves that take another function as an argument, add some functionality, and then return another function. Decorators allow you to wrap another function to modify its behavior.
-
Function Basics: In Python, functions are first-class citizens, which means they can be passed around and used as arguments just like any other object (e.g., integers, strings).
-
Syntax: Decorators use the
@decorator_namesyntax above the function definition. It's a cleaner and more readable way to apply decorators compared to the traditional way of usingfunction_name = decorator_name(function_name). -
Purpose: Common uses of decorators include logging, timing functions, access control, and memoization (caching results for performance).
Let's create a custom decorator to measure the execution time of a function using Python's time module:
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Execution of '{func.__name__}' took {end_time - start_time} seconds")
return result
return wrapper-
Outer Function (
measure_time):- Accepts a function (
func) as an argument. - Defines an inner function (
wrapper) that:- Starts a timer (
start_time) before callingfunc. - Calls
funcwith its arguments (*args,**kwargs) and captures the result. - Stops the timer (
end_time) afterfunccompletes. - Calculates and prints the elapsed time.
- Returns the result of
func.
- Starts a timer (
- Accepts a function (
-
Inner Function (
wrapper):- Executes the wrapped function (
func) and calculates the time it takes to execute.
- Executes the wrapped function (
-
Returning
wrapper:- Returns the
wrapperfunction, which replaces the original function when used as a decorator.
- Returns the
@measure_time
def some_function():
time.sleep(2) # Simulate some work
print("Function executed")
some_function()Function executed
Execution of 'some_function' took 2.0006470680236816 seconds
-
Arguments and Return Values: The
wrapperfunction uses*argsand**kwargsto accept any number of positional and keyword arguments thatfuncmight take. -
Decorating Functions with Parameters: If the decorated function (
func) takes parameters, the decorator (measure_time) should handle them correctly withinwrapper. -
Preserving Function Metadata: To preserve metadata (like
__name__,__doc__, etc.) of the original function, you can usefunctools.wrapsfrom thefunctoolsmodule:from functools import wraps def measure_time(func): @wraps(func) def wrapper(*args, **kwargs): # Implementation remains the same pass return wrapper
Go Back