当前位置: 首页 > news >正文

python中多重继承和泛型 作为模板让子类实现具体业务逻辑

示例代码:

T = TypeVar("T", bound="NoSQLBaseDocument")

# 与 MongoDB 数据库交互的基础文档类
class NoSQLBaseDocument(BaseModel, Generic[T], ABC):
    id: UUID4 = Field(default_factory=uuid.uuid4)

    def __eq__(self, value: object) -> bool:
        if not isinstance(value, self.__class__):
            return False

        return self.id == value.id

    def __hash__(self) -> int:
        return hash(self.id)

这段代码结合使用了 Python 的泛型和多重继承:


第一行代码:泛型类型变量定义

T = TypeVar("T", bound="NoSQLBaseDocument")

通俗解释:

  • TypeVar(“T”):表示我们定义了一个类型变量,名字叫 T,就好比给“类型”起了个名字,方便后续在代码中使用。
  • bound=“NoSQLBaseDocument”:表示这个 T 只能替换为 NoSQLBaseDocument或它的子类。就是说,如果你使用 T,那么它一定得是从 NoSQLBaseDocument 继承来的,不能乱用其他类型。

这里class NoSQLBaseDocument(BaseModel, Generic[T], ABC):又继承了Generic[T]是用到了自引用泛型,让类在定义时能够引用自己作为类型参数

举例说明:

  • 假设你有一个类 ArticleDocument,它继承自 NoSQLBaseDocument,那么 T 可以代表 ArticleDocument(因为ArticleDocumentNoSQLBaseDocument的子类)。
  • 如果你试图让 T 代表一个数字(例如 int),就会不符合要求,因为 int 不是 NoSQLBaseDocument 或它的子类。

可以理解为:

“T 就像一个占位符,表示‘某种文档类型’,但这个文档类型必须是 NoSQLBaseDocument 或它的后代。”


第二行代码:定义基础文档类

class NoSQLBaseDocument(BaseModel, Generic[T], ABC):
    id: UUID4 = Field(default_factory=uuid.uuid4)

这行代码同时用了多重继承泛型,我们逐部分解释:

  1. 继承自 BaseModel

    • 意思:这个类继承了 Pydantic 的 BaseModel,可以利用它提供的数据验证、序列化等功能。
    • 举例:就像你有一个模具,保证所有“文档”数据符合一定的格式,比如字段类型和默认值。
  2. 继承自 Generic[T]

    • 意思:这表示 NoSQLBaseDocument 是一个泛型类,它可以在定义中使用 T。这样,当其他类继承它时,类型检查器就知道它们返回的对象一定和 T 有关。
    • 举例:假设你定义了一个 ArticleDocument 类继承自 NoSQLBaseDocument。此时,T 就自动代表 ArticleDocument。如果调用 ArticleDocument 中的某个方法返回 T,那么类型检查器会认为返回的就是 ArticleDocument 类型,而不是仅仅一个通用的文档。
  3. 继承自 ABC (Abstract Base Class)

    • 意思:这表示 NoSQLBaseDocument 是一个抽象类,不能直接创建实例,只能用来让其它类继承并实现具体功能。
    • 举例:就像一个工厂设计图,你不能直接拿来用,必须先制造出具体的产品,比如 UserDocumentArticleDocument
  4. 字段 id 的定义

    id: UUID4 = Field(default_factory=uuid.uuid4)
    
    • 意思:定义了一个名为 id 的字段,其类型为 UUID4,默认值是调用 uuid.uuid4() 生成的一个随机唯一标识符。
    • 举例说明
      • 如果你创建一个文档对象,例如:
        doc = ArticleDocument(...)
        
        而你没有给 id 赋值,系统会自动生成一个 id,可能是 "123e4567-e89b-12d3-a456-426614174000" 这样的字符串。
      • 就好比你制作一个产品,每个产品都有一个自动生成的序列号,不需要你手动输入。

综合举例

假设我们有两个具体文档类:

# 定义具体文档类1:文章
class ArticleDocument(NoSQLBaseDocument):
    title: str
    content: str

# 定义具体文档类2:用户
class UserDocument(NoSQLBaseDocument):
    first_name: str
    last_name: str
  • 在这两个类中,由于它们都继承自 NoSQLBaseDocument,因此自动拥有一个 id 字段,且这个 id 会自动生成一个唯一值。

  • 当你调用 ArticleDocument 中的某个方法,类型检查器就知道这里的 T 实际上是 ArticleDocument。比如你写了一个 get_or_create 类方法返回 T,那么在 ArticleDocument.get_or_create(...) 调用时,返回的对象类型就是 ArticleDocument

数值例子:

  • 如果你创建了两个 ArticleDocument 实例:
    • article1 自动生成 id = "1111-2222-3333-4444"
    • article2 自动生成 id = "5555-6666-7777-8888"
  • 使用 Generic[T],当你调用 ArticleDocument.get_or_create(title="Python教程"),类型检查器会确认返回的是 ArticleDocument 类型,且你可以安全地使用 article1.title 等属性。

总的来说,这两行代码结合使用了 Python 的泛型和多重继承:

  • 泛型(Generic[T]):使得类可以在方法返回值和类型提示中使用 T,从而保证具体子类类型的一致性。
  • 多重继承:同时继承了 BaseModel(数据验证)、Generic[T](泛型支持)和 ABC(抽象基类),让这个基础文档类既能保证数据格式,又能作为模板让子类实现具体业务逻辑。

相关文章:

  • MySQL 基础学习文档
  • 李宏毅NLP-1-课程介绍
  • Excel导出工具类--复杂的excel功能导出(使用自定义注解导出)
  • C++实现线程安全的队列
  • 【Spring】第二弹:通过反射机制初步理解 IoC
  • C++从入门到入土(八)——多态的原理
  • 【GIS】重要技术3DGS
  • 改变一生的思维模型【12】笛卡尔思维模型
  • 【嵌入式学习】计算机组成原理-二进制存储基础
  • Spring Boot 的自动装配
  • 几种常见的激活函数解析
  • Vue学习笔记集--scoped组件
  • Elasticsearch面试题
  • 基于ssm的电子病历系统(全套)
  • 嵌入式项目代码架构与分层
  • 【AI 加持下的 Python 编程实战 2_04】第三章:GitHub Copilot 在 Python 函数设计中的正确打开方式(含本地实操)
  • python局部变量和全局变量
  • 深入理解 C++20 中的 `std::shared_ptr` 原子操作
  • JDK 动态代理和 CGLIB 动态代理
  • 新能源电站系统建设提速!麒麟信安操作系统驱动光伏风电双领域安全升级
  • 训练孩子的科学思维,上海虹口推出“六个一百”旗舰工程
  • 寒武纪陈天石:公司的产品力获得了行业客户广泛认可,芯片市场有望迎来新增量需求
  • 江西省市场监管局原局长谢来发被双开:违规接受旅游活动安排
  • 香港暂停进口美国北达科他州一地区禽肉及禽类产品
  • 中美日内瓦经贸会谈联合声明
  • 年轻小将绽放光芒!中国短跑男女接力队直通东京世锦赛