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

Python 中的 Mixin

Mixin 是 OOP 中的一种工具,一个用于传递一种特定行为的容器,多个类可以共享该行为,而无需建立“ is-a”(父子)关系,同时保持它们之间的松耦合

Python 依赖多重继承作为底层机制来实现 Mixin

Python 的 mixin 是具有特殊含义的普通类,和普通类之间没有语法差异——区别纯粹是语义上的

继承的缺点

过度泛化:当基类的范围变得过于宽泛时,子类就会开始继承不必要的特性

Erlang的创建者乔·阿姆斯特朗在接受Coders at Work的采访时,巧妙地描述了这个问题:

因为面向对象语言的问题在于,它们自带了各种隐式环境。你想要一根香蕉,结果得到的却是一只叼着香蕉的大猩猩和整片丛林

—乔·阿姆斯特朗

更好的方法是根据类的作用而不是其本身来设计类

这意味着优先考虑组合而不是继承,并将职责委托给更小、更专注的组件

mixin 是一把双刃剑

特点

class SerializableMixin:def serialize(self) -> dict:if hasattr(self, "__slots__"):return {name: getattr(self, name)for name in self.__slots__}else:return vars(self)
  • 命名规范:并非强制要求,类名以Mixin结尾
  • 普通类:由于 mixin 旨在提供独立、可复用的功能(而非强制继承结构),因此它们通常没有任何父类。这最大限度地减少了它们的作用域,并降低了在多重继承场景中名称解析错误的可能性

万事无绝对,有时也可能相反,将各个 Mixin 共同的部分收集到一个父类中可能有助于维护,如 Django 提供的 PermissionRequiredMixinLoginRequiredMixin,都继承AccessMixin

  • 单一职责:一个 mixin 类只有一个职责
  • 无状态性: Mixin 很少定义自己的构造函数__init__()或实例属性,这使得它们可以通过多重继承安全地与其他类集成,而不会发生冲突。Mixin 类封装的行为仅依赖于外部状态。Mixin 通常依赖于其混合到的类的属性。
  • 非独立实体: Mixin 旨在为其他类添加新的或修改的行为。它们通常独立存在时没有任何意义,因此几乎不会直接实例化 mixin 类

Mixin 单独使用没有作用:

import json
class JSONSerializableMixin:def as_json(self) -> str:return json.dumps(vars(self))>>> mixin_instance = JSONSerializableMixin()
>>> mixin_instance.as_json()
'{}'

只有继承之后会发挥作用:

from dataclasses import dataclass@dataclass
class User(JSONSerializableMixin):user_id: intemail: str>>> User(555, "jdoe@example.com").as_json()
'{"user_id": 555, "email": "jdoe@example.com"}'

继承🆚Mixin

继承通常可以从两个方面理解:

  1. 实现代码复用
  2. 作为建立子类型关系的工具

这两种用法也分别称为实现继承接口继承

mixin 主要侧重于代码复用,而非强“is a”关系

继承自 mixin 的类不会成为其子类型,只是使用其功能。

由于 mixin 并非旨在实现多态性,因此将其视为可与其基类互换通常违反了里氏代换原则

抽象类🆚Mixin

相同点:二者都是基础元素,旨在通过继承与一个或多个目标类组合

不同点:抽象类旨在被子类化以多态方式使用。它们通常具有父类

此外,声明 ABC 需要使用特殊的元类装饰器,Python 可以利用它们运行额外的检查:

from abc import ABC, abstractmethod
from typing import Anyclass Serializer(ABC):@abstractmethoddef serialize(self, data: Any) -> str:pass>>> abc_instance = Serializer()
TypeError: Can't instantiate abstract class Serializer
⮑ without an implementation for abstract method 'serialize'

使用抽象基类来定义算法的核心实现,同时在子类之间强制使用通用接口。这使得抽象基类 (ABC) 特别适合实现模板方法模式

Mixin 继承顺序

利用 Django 提供的 Mixin 与 ListView 实现一个图书列表页面:

class BookListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):

不必严格依赖 MRO 就能利用好 mixin 。mixin 在与其他基类一起使用时才能发挥最大作用,但这有时会导致一些意想不到的行为

常见问题

  1. 过度使用:一个类继承的 Mixin 不要过多,功能繁杂可能导致其成为上帝对象
  2. 继承顺序错误:由于 Python 采用 C3 超类线性化算法决定 MRO( 靠左优先的类继承),需处理好 mixin 的继承顺序,否则不同 mixin 功能可能有冲突、重叠,甚至相互抵消

未完待续

http://www.dtcms.com/a/322930.html

相关文章:

  • 二十、MySQL-DQL-条件查询
  • 第八章:终极合体 —— 实现智能一键分组
  • 【Python 工具人快餐 · 第 1 份】
  • 【代码随想录|232.用栈实现队列、225.用队列实现栈、20.有效的括号、1047.删除字符串中的所有相邻重复项】
  • 第05章 排序与分页
  • 模板方法模式:优雅封装算法骨架
  • Python-UV-portry项目管理流程
  • redis8.0.3部署于mac
  • C++ 中的智能指针
  • Python 继承和多态
  • ElaWidgetTools qt5+vs2019编译
  • 1.JavaScript 介绍
  • 基于STM32的智能电表设计与实现
  • 计算机组成原理2-4-1:浮点数的表示
  • Linux 安装 JDK 8u291 教程(jdk-8u291-linux-x64.tar.gz 解压配置详细步骤)​
  • 【c++】探秘Loop机制:C++中优雅的双向数据交互模式
  • 低速CAN 高速CAN是否兼容?
  • 功能测试详解
  • 【面试题】cookie和session 的区别
  • Ubuntu下Nginx的部署后端项目(Java为例),配置Nginx代理
  • 自编教材实操课程学习笔记
  • 商品、股指及ETF期权五档盘口Tick级与分钟级历史行情数据多维解析
  • dify离线插件安装
  • Spring Boot Starter 自动化配置原理深度剖析
  • 【工具变量】地市人力资本水平数据集(2003-2023年)
  • 聊聊经常用的微服务
  • Java 枚举解析:从基础到进阶的知识点与注意事项
  • 【完整源码+数据集+部署教程】植物生长阶段检测系统源码和数据集:改进yolo11-rmt
  • gRPC for C++ 实战全流程 —— 从零搭建到同步/异步服务
  • vw和vh:CSS中的视口相对单位