|
|
@@ -0,0 +1,229 @@
|
|
|
+# Mixin?
|
|
|
+
|
|
|
+## Mixin 的概念
|
|
|
+
|
|
|
+**Mixin** 是一种编程模式,源自面向对象编程,特别是在 Python 中广泛使用。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 命名来源
|
|
|
+
|
|
|
+### 1. **语义理解**
|
|
|
+
|
|
|
+- **Mix** = 混合
|
|
|
+- **-in** = 混入
|
|
|
+- **Mixin** = **混入类**(将功能"混入"到其他类中)
|
|
|
+
|
|
|
+### 2. **设计意图**
|
|
|
+
|
|
|
+```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?
|
|
|
+
|
|
|
+### 1. **功能解耦**
|
|
|
+
|
|
|
+每个 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()` |
|
|
|
+
|
|
|
+### 2. **代码复用**
|
|
|
+
|
|
|
+```python
|
|
|
+# 多个 Result 类可以共享相同的 Mixin
|
|
|
+
|
|
|
+class PPStructureResult(JsonMixin, MarkdownMixin, ImgMixin):
|
|
|
+ """PP-Structure 结果"""
|
|
|
+ pass
|
|
|
+
|
|
|
+class PaddleOCRVLResult(JsonMixin, MarkdownMixin, ImgMixin):
|
|
|
+ """PaddleOCR-VL 结果"""
|
|
|
+ pass
|
|
|
+
|
|
|
+# 两者都自动获得了 JSON/Markdown/Image 的导出能力!
|
|
|
+```
|
|
|
+
|
|
|
+### 3. **灵活组合**
|
|
|
+
|
|
|
+```python
|
|
|
+# 🎯 根据需求自由组合 Mixin
|
|
|
+
|
|
|
+# 场景 1: 表格识别 - 需要 HTML
|
|
|
+class TableResult(JsonMixin, HtmlMixin, XlsxMixin):
|
|
|
+ pass
|
|
|
+
|
|
|
+# 场景 2: 文本识别 - 不需要 HTML
|
|
|
+class TextResult(JsonMixin, MarkdownMixin):
|
|
|
+ pass
|
|
|
+
|
|
|
+# 场景 3: 目标检测 - 需要可视化图像
|
|
|
+class DetectionResult(JsonMixin, ImgMixin):
|
|
|
+ pass
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Mixin 的实现原理
|
|
|
+
|
|
|
+### 1. **抽象方法 + 具体实现**
|
|
|
+
|
|
|
+```python
|
|
|
+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)
|
|
|
+```
|
|
|
+
|
|
|
+### 2. **多重继承的方法解析顺序 (MRO)**
|
|
|
+
|
|
|
+```python
|
|
|
+class Result(JsonMixin, MarkdownMixin, ImgMixin, BasePipeline):
|
|
|
+ pass
|
|
|
+
|
|
|
+# Python 会按照 C3 线性化算法确定方法调用顺序
|
|
|
+print(Result.__mro__)
|
|
|
+# (<class 'Result'>,
|
|
|
+# <class 'JsonMixin'>,
|
|
|
+# <class 'MarkdownMixin'>,
|
|
|
+# <class 'ImgMixin'>,
|
|
|
+# <class 'BasePipeline'>,
|
|
|
+# <class 'object'>)
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## PaddleX 中的 Mixin 架构
|
|
|
+
|
|
|
+### 完整继承关系
|
|
|
+
|
|
|
+```python
|
|
|
+# 基础结果类
|
|
|
+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 模式的优势
|
|
|
+
|
|
|
+### 1. ✅ **单一职责原则**
|
|
|
+每个 Mixin 只负责一个功能领域
|
|
|
+
|
|
|
+### 2. ✅ **开闭原则**
|
|
|
+无需修改现有代码,通过添加新 Mixin 扩展功能
|
|
|
+
|
|
|
+```python
|
|
|
+# 新增 PDF 导出功能
|
|
|
+class PdfMixin:
|
|
|
+ def save_to_pdf(self, save_path: str):
|
|
|
+ ...
|
|
|
+
|
|
|
+# 只需修改继承列表
|
|
|
+class EnhancedResult(JsonMixin, MarkdownMixin, PdfMixin):
|
|
|
+ pass
|
|
|
+```
|
|
|
+
|
|
|
+### 3. ✅ **避免菱形继承问题**
|
|
|
+通过抽象方法和明确的接口设计避免冲突
|
|
|
+
|
|
|
+### 4. ✅ **测试友好**
|
|
|
+可以独立测试每个 Mixin 的功能
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 常见 Mixin 命名规范
|
|
|
+
|
|
|
+| 命名风格 | 示例 | 说明 |
|
|
|
+|---------|------|------|
|
|
|
+| **功能 + Mixin** | `JsonMixin`, `LoggingMixin` | ✅ 最常见 |
|
|
|
+| **Able 后缀** | `Serializable`, `Drawable` | Java 风格 |
|
|
|
+| **Interface 前缀** | `ISerializable` | C# 风格 |
|
|
|
+
|
|
|
+PaddleX 采用 **`功能名 + Mixin`** 的命名方式,清晰表明这是可混入的功能模块。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 总结
|
|
|
+
|
|
|
+**Mixin** 命名的含义:
|
|
|
+
|
|
|
+1. 📦 **Mix** = 混合不同功能
|
|
|
+2. 🔌 **-in** = 插入到类中
|
|
|
+3. 🎯 **目的** = 通过组合而非继承实现功能复用
|
|
|
+
|
|
|
+这种模式让 PaddleX 的结果类能够**灵活组合**各种导出格式,同时保持代码的**清晰性**和**可维护性**!
|