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

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(抽象基类),让这个基础文档类既能保证数据格式,又能作为模板让子类实现具体业务逻辑。

http://www.kler.cn/a/589534.html

相关文章:

  • Linux错误(2)程序触发SIGBUS信号分析
  • 基于Springboot+Typst的PDF生成方案,适用于报告打印/标签打印/二维码打印等
  • 开源文档管理系统 Paperless-ngx
  • 【后端开发面试题】每日 3 题(十三)
  • 利用golang embed特性嵌入前端资源问题解决
  • 【经验分享】SpringBoot集成WebSocket开发-03 使用WebSocketSession为每个对话存储独立信息
  • Vue3中正确解析RefImpl对象
  • Hyperlane:轻量、高效、安全的 Rust Web 框架新选择
  • Java 大视界 -- Java 大数据机器学习模型的对抗攻击与防御技术研究(137)
  • 为什么手机上用 mA 和 mAh 来表示功耗和能耗?
  • java学习总结:JSP、Servlet
  • vue3项目如何使用keepAlive?如何实现回退到这个页面时不刷新,跳转至这个页面时会刷新?
  • Redis主从集群和哨兵集群
  • CML(Current Mode Logic)电平详解
  • MyBatis XMLMapperBuilder 是如何解析 SQL 映射文件的? 它读取了哪些信息?
  • docker安装rabbitmq
  • pyyaml_include 2.x 版本使用说明
  • Spring Cloud Gateway 生产级实践:高可用 API 网关架构与流量治理解析
  • Linux应用软件编程(多任务:进程间通信)
  • Excel VBA实现智能合并重复元器件数据(型号去重+数量累加)