乐闻世界logo
搜索文章和话题

How does Python decorator work?

2月17日 23:50

A Decorator is a powerful design pattern in Python that allows you to add additional functionality to a function without modifying its original code. Essentially, a decorator is a function that takes a function as a parameter and returns a new function.

Working Principle

1. Decorator Syntax Sugar

python
@decorator def my_function(): pass

The code above is equivalent to:

python
my_function = decorator(my_function)

2. Simple Decorator Example

python
def simple_decorator(func): def wrapper(): print("Before function execution") func() print("After function execution") return wrapper @simple_decorator def say_hello(): print("Hello, World!") say_hello()

Output:

shell
Before function execution Hello, World! After function execution

3. Decorator with Parameters

python
def decorator_with_args(func): def wrapper(*args, **kwargs): print(f"Parameters: args={args}, kwargs={kwargs}") result = func(*args, **kwargs) return result return wrapper @decorator_with_args def add(a, b): return a + b print(add(3, 5)) # Output: Parameters: args=(3, 5), kwargs={} \n 8

4. Decorator with Custom Parameters

python
def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(3) def greet(name): print(f"Hello, {name}!") greet("Python") # Will print three times

5. Using functools.wraps to Preserve Metadata

python
from functools import wraps def logging_decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"Calling function: {func.__name__}") return func(*args, **kwargs) return wrapper @logging_decorator def calculate(x, y): """Calculate the sum of two numbers""" return x + y print(calculate.__name__) # Output: calculate print(calculate.__doc__) # Output: Calculate the sum of two numbers

Practical Application Scenarios

1. Timer Decorator

python
import time from functools import wraps def timer(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} execution time: {end_time - start_time:.4f} seconds") return result return wrapper @timer def slow_function(): time.sleep(2) return "Completed" slow_function()

2. Cache Decorator

python
from functools import wraps def memoize(func): cache = {} @wraps(func) def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper @memoize def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(100)) # Fast calculation

3. Permission Verification Decorator

python
from functools import wraps def require_permission(permission): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): user_permissions = kwargs.get('permissions', []) if permission in user_permissions: return func(*args, **kwargs) else: raise PermissionError(f"Requires {permission} permission") return wrapper return decorator @require_permission('admin') def delete_user(user_id, permissions): print(f"Deleting user {user_id}") delete_user(1, permissions=['admin']) # Normal execution delete_user(1, permissions=['user']) # Throws permission error

Class Decorator

python
class CountCalls: def __init__(self, func): self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.count += 1 print(f"Call count: {self.count}") return self.func(*args, **kwargs) @CountCalls def say_hi(): print("Hi!") say_hi() # Call count: 1 say_hi() # Call count: 2

Multiple Decorators Execution Order

python
def decorator1(func): def wrapper(): print("Decorator 1 - Before") func() print("Decorator 1 - After") return wrapper def decorator2(func): def wrapper(): print("Decorator 2 - Before") func() print("Decorator 2 - After") return wrapper @decorator1 @decorator2 def my_function(): print("Function execution") my_function()

Output:

shell
Decorator 1 - Before Decorator 2 - Before Function execution Decorator 2 - After Decorator 1 - After

Key Points

  1. Decorator Essence: A function that takes a function and returns a new function
  2. Syntax Sugar: @decorator is shorthand for func = decorator(func)
  3. Parameter Passing: Use *args, **kwargs to ensure decorators work for any function
  4. Metadata Preservation: Use @wraps(func) to preserve original function metadata
  5. Execution Order: With multiple decorators, apply from bottom to top, execute from top to bottom
  6. Closures: Decorators use closure properties to access external variables
  7. Class Decorators: Implemented by defining the __call__ method

Decorators are an elegant way to implement cross-cutting concerns (such as logging, caching, permission verification) in Python, following the open-closed principle and making code more modular and maintainable.

标签:Python