全面 Python 类装饰器与 OOP 模式指南
目录
OOP 核心概念
四大特性
class Animal:
# 封装
def __init__(self, name):
self._name = name # 受保护属性
# 继承
class Dog(Animal):
def bark(self):
print("Woof!")
# 多态
def make_sound(self):
raise NotImplementedError
# 抽象
from abc import ABC, abstractmethod
class Bird(ABC):
@abstractmethod
def fly(self):
pass
类变量 vs 实例变量
class Counter:
count = 0 # 类变量
def __init__(self):
self.id = id(self) # 实例变量
Counter.count += 1
MVC/MTV 架构模式
Django 的 MTV 模式
| 组件 | 对应传统 MVC | 职责 |
|---|---|---|
| Model | Model | 数据存取 |
| Template | View | 展示逻辑 |
| View | Controller | 业务逻辑 |
工作流程
- 请求 → URL 路由
- View 处理请求
- Model 操作数据库
- Template 渲染响应
类成员详解
三种方法对比
| 类型 | 装饰器 | 首参数 | 访问权限 |
|---|---|---|---|
| 实例方法 | 无 | self | 实例+类 |
| 类方法 | @classmethod | cls | 仅类 |
| 静态方法 | @staticmethod | 无 | 无 |
代码示例
class MyClass:
class_var = "类变量"
def __init__(self, val):
self.instance_var = val
def normal_method(self):
print(f"实例方法访问 {self.instance_var}")
@classmethod
def class_method(cls):
print(f"类方法访问 {cls.class_var}")
@staticmethod
def static_method():
print("独立静态方法")
装饰器完整参考
核心装饰器
# 属性管理
class Circle:
@property
def area(self):
return 3.14 * self.radius**2
@area.setter
def area(self, value):
self.radius = (value / 3.14)**0.5
# 类构建
@dataclass
class Point:
x: float
y: float
# 抽象接口
class Database(ABC):
@abstractmethod
def connect(self):
pass
进阶装饰器
# 缓存优化
from functools import cached_property, lru_cache
class Data:
@cached_property
def calculated(self):
return expensive_computation()
@lru_cache(maxsize=32)
def get(self, key):
return query_database(key)
# 方法重载
from functools import singledispatchmethod
class Processor:
@singledispatchmethod
def handle(self, data):
raise NotImplementedError
@handle.register(str)
def _(self, text):
return f"String: {text}"
实战应用示例
工厂模式
class Vehicle:
registry = {}
@classmethod
def register(cls, name):
def wrapper(subclass):
cls.registry[name] = subclass
return subclass
return wrapper
@classmethod
def create(cls, name, **kwargs):
return cls.registry[name](**kwargs)
@Vehicle.register("car")
class Car(Vehicle):
pass
my_car = Vehicle.create("car")
属性验证
class User:
def __init__(self, email):
self._email = email
@property
def email(self):
return self._email
@email.setter
def email(self, value):
if not "@" in value:
raise ValueError("Invalid email")
self._email = value
最佳实践总结
- 封装优先:多用
@property保护数据 - 灵活构造:
@classmethod实现多种构造方式 - 保持简洁:
@dataclass减少样板代码 - 明确契约:
@abstractmethod定义清晰接口 - 性能优化:合理使用缓存装饰器
提示:装饰器可组合使用(如
@classmethod+@property),但需注意执行顺序
实战应用示例
functools.wraps(func)核心作用
@functools.wraps(func) 是装饰器开发的关键工具,用于保留被装饰函数的元信息,解决装饰器导致的元数据丢失问题。
问题演示(不使用wraps)
def bad_decorator(func):
def wrapper(*args, **kwargs):
"""包装函数的docstring"""
return func(*args, **kwargs)
return wrapper
@bad_decorator
def say_hello(name):
"""原始函数的docstring"""
print(f"Hello, {name}!")
# 元信息测试
print(say_hello.__name__) # 输出: wrapper(错误!)
print(say_hello.__doc__) # 输出: 包装函数的docstring(错误!)
导致的问题
- 函数名变为装饰器内部函数名(
wrapper) - 文档字符串被覆盖
- 破坏依赖元信息的工具(调试器、文档生成器等)
解决方案(使用wraps)
import functools
def good_decorator(func):
@functools.wraps(func) # 关键修复
def wrapper(*args, **kwargs):
"""包装函数的docstring"""
return func(*args, **kwargs)
return wrapper
@good_decorator
def say_hello(name):
"""原始函数的docstring"""
print(f"Hello, {name}!")
# 元信息测试
print(say_hello.__name__) # 输出: say_hello(正确)
print(say_hello.__doc__) # 输出: 原始函数的docstring(正确)
保留的元信息
| 属性 | 说明 | 示例值 |
|---|---|---|
__name__ |
函数名 | "say_hello" |
__doc__ |
文档字符串 | """原始函数的docstring""" |
__module__ |
所属模块 | __main__ |
__annotations__ |
类型注解 | {'name': <class 'str'>} |
__dict__ |
自定义属性 | 用户定义的属性 |
实际应用场景
def log_call(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用: {func.__name__}") # 显示真实函数名
return func(*args, **kwargs)
return wrapper
Web框架路由(Flask示例)
@app.route('/')
@auth_required # 需要保留元信息才能正确路由
def home():
return "Welcome"
文档生成
def api_endpoint(func):
@functools.wraps(func)
def wrapper():
return func()
return wrapper
@api_endpoint
def get_users():
"""获取用户列表"""
pass
# help(get_users) 能显示真实文档
实现原理
简化版实现
def wraps(original_func):
def wrapper(decorator_func):
# 复制所有重要属性
decorator_func.__name__ = original_func.__name__
decorator_func.__doc__ = original_func.__doc__
decorator_func.__module__ = original_func.__module__
# ...复制其他属性...
return decorator_func
return wrapper
实际功能
- 将原函数的元数据深拷贝到包装函数
- 处理特殊属性(如
__qualname__) - 兼容各种Python版本
最佳实践
- 必须使用的场景:
- 任何生产环境装饰器
- 会被其他工具(如Sphinx、Flask)使用的函数
- 可以不用的场景:
- 临时调试装饰器
- 明确需要覆盖元信息的情况
- 推荐写法:
from functools import wraps
def decorator(func):
@wraps(func) # 清晰明确的写法
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
扩展知识
保留签名(Python 3.3+)
from inspect import signature
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.__signature__ = signature(func) # 保留参数签名
return wrapper
通过
@functools.wraps+inspect.signature可以完美保留函数的所有特征