Understanding Python Decorators: Introduction, Common Examples, and Summary
This article introduces Python decorators, explains their purpose, and provides practical examples of common decorators such as @staticmethod, @property, @lru_cache, @wraps, @retry, @contextmanager, @dataclass, @cached_property, @singledispatch, and @timeit, concluding with a summary of their benefits for clean, maintainable code.
1. Introduction to Decorators Decorators are functions that accept another function as an argument and return a new function, allowing modification of behavior such as logging, performance testing, or transaction handling. They are applied using the @ syntax before a function definition.
2. Decorator Examples
@staticmethod and @classmethod Use when a method does not need to access instance or class state.
class MathUtil:
@staticmethod
def add(a, b):
return a + b
@classmethod
def subtract(cls, a, b):
return a - b
print(MathUtil.add(1, 2)) # 输出 3
print(MathUtil.subtract(3, 1)) # 输出 2@property Use to turn a method into a read‑only attribute, optionally providing a setter for controlled modification.
class Person:
def __init__(self, age):
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self._age = value
p = Person(30)
print(p.age) # 输出 30
p.age = 35
print(p.age) # 输出 35@lru_cache Use to cache function results and avoid repeated computation, especially useful for recursive or intensive tasks.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 输出 55@functools.wraps Use inside a decorator to preserve the wrapped function's metadata such as name and docstring.
from functools import wraps
def debug(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@debug
def say_hello(name):
"""Say hello to someone."""
print(f"Hello, {name}!")
say_hello("Alice") # 输出 Calling say_hello
# Hello, Alice!@retry Use to automatically retry a function that may fail, such as network requests.
from functools import wraps
def retry(times=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Failed, retrying... {e}")
raise Exception("Max retries exceeded")
return wrapper
return decorator@retry() Example of a function that randomly fails and can be wrapped with a retry mechanism.
def get_data(url):
# 模拟网络请求,这里使用随机抛出异常来模拟失败情况
import random
if random.random() < 0.5:
raise Exception("Network error")
return "Data retrieved"
print(get_data("http://example.com")) # 输出 Data retrieved@contextmanager Use to create a context manager that handles resource acquisition and release automatically.
from contextlib import contextmanager
@contextmanager
def managed_file(name):
try:
f = open(name, 'r')
yield f
finally:
f.close()
with managed_file('test.txt') as f:
for line in f:
print(line) # 假设 test.txt 中有内容@dataclass Use to simplify class definitions by automatically generating __init__, __repr__, __eq__, and other methods.
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
p = Point(1, 2)
print(p) # 输出 Point(x=1, y=2)@cached_property Use to cache the result of a property method after the first access.
from functools import cached_property
class Circle:
def __init__(self, radius):
self.radius = radius
@cached_property
def area(self):
return 3.14 * (self.radius ** 2)
c = Circle(5)
print(c.area) # 输出 78.5@singledispatch Use to implement generic functions that dispatch based on the type of the first argument.
from functools import singledispatch
@singledispatch
def add(a, b):
raise NotImplementedError("Unsupported type")
@add.register(int)
def _(a, b):
return a + b
@add.register(str)
def _(a, b):
return a + b
print(add(1, 2)) # 输出 3
print(add("Hello, ", "World!")) # 输出 Hello, World!@timeit Use to measure the execution time of a function for performance analysis.
import time
def timeit(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.6f}s")
return result
return wrapper
@timeit
def sleep_and_return(seconds):
time.sleep(seconds)
return "Done sleeping"
print(sleep_and_return(1)) # 输出 sleep_and_return took 1.000000s
# 输出 Done sleeping3. Summary Decorators can simplify code, extend functionality, and make programs easier to maintain and evolve. The examples above aim to help you understand and apply decorators effectively, enhancing your Python programming skills.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.