Mixin 是一种编程模式,源自面向对象编程,特别是在 Python 中广泛使用。
# 🎯 Mixin 的核心思想:组合而非继承
class BasePipeline:
"""基础 Pipeline 类"""
pass
# ❌ 传统继承:功能耦合严重
class Pipeline(BasePipeline, JsonHandler, ImageHandler, MarkdownHandler):
# 所有功能都继承,即使不需要
pass
# ✅ Mixin 模式:按需混入功能
class TableRecognitionResult(BasePipeline, JsonMixin, HtmlMixin, MarkdownMixin):
"""表格识别结果 - 只混入需要的功能"""
pass
class OCRResult(BasePipeline, JsonMixin, ImgMixin):
"""OCR 结果 - 不需要 HTML/Markdown"""
pass
每个 Mixin 类负责一项独立功能:
| Mixin 类 | 职责 | 提供的方法 |
|---|---|---|
JsonMixin |
JSON 序列化 | .json, save_to_json() |
ImgMixin |
图像处理 | .img, save_to_img() |
MarkdownMixin |
Markdown 导出 | .markdown, save_to_markdown() |
HtmlMixin |
HTML 生成 | .html, save_to_html() |
CSVMixin |
CSV 导出 | .csv, save_to_csv() |
# 多个 Result 类可以共享相同的 Mixin
class PPStructureResult(JsonMixin, MarkdownMixin, ImgMixin):
"""PP-Structure 结果"""
pass
class PaddleOCRVLResult(JsonMixin, MarkdownMixin, ImgMixin):
"""PaddleOCR-VL 结果"""
pass
# 两者都自动获得了 JSON/Markdown/Image 的导出能力!
# 🎯 根据需求自由组合 Mixin
# 场景 1: 表格识别 - 需要 HTML
class TableResult(JsonMixin, HtmlMixin, XlsxMixin):
pass
# 场景 2: 文本识别 - 不需要 HTML
class TextResult(JsonMixin, MarkdownMixin):
pass
# 场景 3: 目标检测 - 需要可视化图像
class DetectionResult(JsonMixin, ImgMixin):
pass
class JsonMixin:
"""JSON 功能混入类"""
# ✅ 抽象方法 - 由子类实现
@abstractmethod
def _to_json(self) -> Dict[str, Any]:
"""子类必须实现数据转换逻辑"""
raise NotImplementedError
# ✅ 具体方法 - Mixin 提供通用功能
@property
def json(self) -> Dict[str, Any]:
"""获取 JSON 数据"""
return self._to_json()
def save_to_json(self, save_path: str):
"""保存 JSON 文件"""
json_data = self._to_json()
self._json_writer.write(save_path, json_data)
class Result(JsonMixin, MarkdownMixin, ImgMixin, BasePipeline):
pass
# Python 会按照 C3 线性化算法确定方法调用顺序
print(Result.__mro__)
# (<class 'Result'>,
# <class 'JsonMixin'>,
# <class 'MarkdownMixin'>,
# <class 'ImgMixin'>,
# <class 'BasePipeline'>,
# <class 'object'>)
# 基础结果类
class BasePipelineResult:
"""所有 Pipeline 结果的基类"""
def __init__(self):
self._save_funcs = [] # 收集所有保存方法
def save_all(self, save_path: str):
"""调用所有混入的保存方法"""
for save_func in self._save_funcs:
save_func(save_path)
# PP-Structure V3 结果
class PPStructureResult(
JsonMixin, # 提供 .json, save_to_json()
MarkdownMixin, # 提供 .markdown, save_to_markdown()
ImgMixin, # 提供 .img, save_to_img()
BasePipelineResult
):
def _to_json(self):
"""实现 JSON 转换逻辑"""
return {"res": self.data}
def _to_markdown(self):
"""实现 Markdown 转换逻辑"""
return {"markdown_texts": self.md_content}
def _to_img(self):
"""实现图像转换逻辑"""
return {"layout": self.layout_img}
# 使用示例
result = pipeline.predict(image)
result.json # 获取 JSON
result.markdown # 获取 Markdown
result.img # 获取可视化图像
result.save_all("./output") # 一次性保存所有格式
每个 Mixin 只负责一个功能领域
无需修改现有代码,通过添加新 Mixin 扩展功能
# 新增 PDF 导出功能
class PdfMixin:
def save_to_pdf(self, save_path: str):
...
# 只需修改继承列表
class EnhancedResult(JsonMixin, MarkdownMixin, PdfMixin):
pass
通过抽象方法和明确的接口设计避免冲突
可以独立测试每个 Mixin 的功能
| 命名风格 | 示例 | 说明 |
|---|---|---|
| 功能 + Mixin | JsonMixin, LoggingMixin |
✅ 最常见 |
| Able 后缀 | Serializable, Drawable |
Java 风格 |
| Interface 前缀 | ISerializable |
C# 风格 |
PaddleX 采用 功能名 + Mixin 的命名方式,清晰表明这是可混入的功能模块。
Mixin 命名的含义:
这种模式让 PaddleX 的结果类能够灵活组合各种导出格式,同时保持代码的清晰性和可维护性!