Python编程中类与类的关系详解
前言写代码写到一定程度问题就不再是怎么写一个类而是这几个类之间到底该是什么关系。常见的关系有三类继承inheritance、组合composition、依赖dependency。名字都好懂难的是选哪个——很多初学者一看两个类有关系就想继承结果继承链越拉越长改一处父类就让一片子类出问题。这里要先纠正一个流传很广的说法继承是面向对象的核心能继承就继承。实际情况正相反设计原则里默认推荐组合继承只在确实满足is-a关系时才用。继承把子类和父类强耦合在一起父类的任何内部改动都可能波及子类组合只是持有另一个对象边界清晰得多。本文讲清这三类关系各自的含义、适用场景和判断标准示例基于 Python 3.8。一、继承is-a子类确实是父类的一种继承的语义是是一种is-a。判断标准很直接子类对象能不能在父类对象出现的任何地方替换使用而不违反使用者的预期。猫是一种动物所以Cat(Animal)合理员工是一种人所以Employee(Person)合理。# 适用于 Python 3.8class Animal:def __init__(self, name):self.name namedef eat(self):return f{self.name} 在吃东西class Cat(Animal): # Cat is-a Animaldef purr(self):return f{self.name} 在打呼噜c Cat(小白)print(c.eat()) # 从父类继承来的print(c.purr()) # 自己特有的继承的好处是复用父类实现并支持运行时多态调用方按Animal的接口写代码传进去的可以是任意子类。代价是耦合——父类改了eat的签名所有子类都得跟着看一遍。二、组合has-a优先考虑的方案组合的语义是有一个has-a一个类把另一个类的实例当作自己的属性通过它来完成工作。它不暴露对方的内部只借用对方的能力。# 适用于 Python 3.8class Engine:def __init__(self, power):self.power powerdef start(self):return f发动机启动功率 {self.power}class Car:def __init__(self, engine, brand):self.engine engine # Car has-a Engineself.brand branddef start(self):# 委托给内部对象而不是继承它的实现return f{self.brand} self.engine.start()car Car(Engine(150), 某品牌)print(car.start())组合的优势Car不需要知道Engine的内部结构只依赖它的公开接口想换一种发动机传入另一个实现了start()的对象即可不用改Car。这就是面向接口而非实现的落地方式也让单元测试可以塞进一个假的发动机。判断口诀如果两个类之间是它有一个它用组合如果它是一种它才考虑继承。拿不准时优先组合。三、依赖uses-a最松的一种关系依赖比组合还松一个类只是在某个方法里临时用到另一个类并不把它存在属性里。关系只存在于调用的那一瞬间A甚至不需要 importB就能接收它。# 适用于 Python 3.8class Report:def __init__(self, rows):self.rows rowsclass Printer: # 依赖只在方法参数里用一下def render(self, report):for row in report.rows:print(row)class Logger: # 组合长期持有def __init__(self, sink):self.sink sink # sink 是对象长期存在def log(self, msg):self.sink.write(msg \n)Printer().render(Report([1, 2, 3]))依赖是最弱的耦合Printer完全不知道Report从哪来、是什么子类只要能读rows就行。这也正是鸭子类型duck typing的体现——不关心类型只关心有没有那个属性或方法。四、把关系画成一张对照表关系别名语义耦合强度典型写法继承is-a子类是父类的一种强class B(A)组合has-a整体持有部分中self.part part聚合has-a弱持有但不独占生命周期中偏弱self.members members依赖uses-a只在方法里临时使用弱def f(self, other)关联knows-a长期知道对方存在中属性或引用其中聚合aggregation与组合composition的区别在生命周期组合里部分随整体一起创建销毁汽车与发动机聚合里部分可以独立存在班级与学生——班级没了学生还在。Python 不强制表达这个区别靠的是代码约定和文档。五、多重继承与 MROPython 允许一个类继承多个父类。查找方法时按方法解析顺序Method Resolution OrderMRO从左到右、广度优先地找可以用Cls.__mro__或Cls.mro()查看。# 适用于 Python 3.8class A:def tag(self):return Aclass B(A):def tag(self):return Bclass C(A):def tag(self):return Cclass D(B, C):def tag(self):return D super().tag()print([k.__name__ for k in D.__mro__]) # [D, B, C, A, object]print(D().tag()) # D Bsuper()在多重继承里指向的是 MRO 里的下一个类不是父类集合。所以协作式cooperative多重继承里每个类都应调用super()才能让链路走完。多重继承能少用就少用最常见的正当用途是混入类mixin——只提供一小段可复用行为不构成完整 is-a。常见坑点坑 1为了复用一段方法就继承。❌class Order(dict):只是想在订单里用字典的取值方式结果继承了一整套字典行为order[x]、order.get()到处可用语义越来越乱。✅ 用组合self.data {}只暴露你需要的方法。坑 2子类没有满足 is-a 却硬继承。❌class Stack(list):—— 栈不是列表的一种它还会意外暴露insert、sort等破坏只能从一端进出的约束。✅ 组合一个列表只提供push/pop/peek。坑 3父类__init__不调用。❌ 子类定义了__init__却忘了super().__init__(...)父类设置的属性全部缺失报AttributeError。✅ 子类__init__第一行调用super().__init__(...)。坑 4把依赖写成全局变量或 import 里的硬引用。❌ 在方法里直接import 某个具体类并new死它想换实现就得改这个类。✅ 通过参数把对象传进来依赖注入的朴素形式或者只依赖一个方法名。坑 5多重继承里只在一个分支写super()。❌ 在D.tag里只写B.tag(self)绕过 MROC的逻辑永不执行。✅ 统一用零参数super()让协作链走完整。坑 6混淆聚合与组合的生命周期。❌ 班级对象销毁时顺手把学生对象也丢弃以为整体没了部分也该没。✅ 想清楚部分是不是独立实体独立就用聚合只保存引用不负责销毁。坑 7用type(x) A判断继承关系。❌if type(obj) Animal:—— 子类实例判断为假。✅ 用isinstance(obj, Animal)。总结场景该选的关系子类能替换父类且语义成立继承is-a想复用一段行为的实现组合has-a只在方法里临时用一下别的对象依赖uses-a部分与整体生命周期一致组合部分可独立存在聚合需要横向复用一小段逻辑混入类mixin一句话总结类与类的关系里继承表达是什么组合表达有什么依赖表达用一下。默认优先组合与依赖只有在 is-a 成立、且确实需要多态替换时才用继承多重继承留给混入这一类明确场景。说明本文的super()、MRO、isinstance行为在 Python 3 中统一且稳定。Python 2 里旧式类不支持零参数super()只有新式类才行Python 2.7 已于 2020 年 1 月 1 日停止维护新代码只写 Python 3。

相关新闻

Spring Boot+Vue旅游资源网站前后端分离开发实战解析

Spring Boot+Vue旅游资源网站前后端分离开发实战解析

做过旅游类后台开发的人应该都清楚,这类系统的核心并不在于功能多花哨,而在于信息流是否顺畅、状态是否闭环、代码是否好改。最近手头刚好在整理一套基于 Java 的旅游资源网站,包含前台浏览、线路查询、预订留言和后端管理几大块内容&#xf…

2026/10/13 3:42:54 阅读更多 →
HDFS机架感知配置实战:从原理到副本安全

HDFS机架感知配置实战:从原理到副本安全

做大数据的人应该都遇到过这种场景:集群明明有几十个节点,机柜也分了七八个,但HDFS的副本就是乱放,数据块经常整整齐齐聚在一台交换机下面,结果某天那台交换机一抖动,一堆block同时告警丢失。这种问题十有八…

2026/10/13 3:42:54 阅读更多 →
AI Agent Skill实战:把可复用流程固化给大模型,告别低效提示词

AI Agent Skill实战:把可复用流程固化给大模型,告别低效提示词

我大概是去年年底才开始认真用上“Skill”这个概念的。在此之前,我一直觉得让 AI 干点正经活,靠的就是把提示词写得越来越长、越来越细。直到我花了一个下午,把一套反复用了七八次的“调研–分析–输出简报”流程,真正固化成一个 …

2026/10/13 3:42:54 阅读更多 →

最新新闻

12寸晶圆产线PB级数据治理:软件定义存储与生命周期管理实践

12寸晶圆产线PB级数据治理:软件定义存储与生命周期管理实践

1. 项目背景与行业痛点1.1 产线数据从“资产”变成“包袱”一条12寸晶圆产线,每天都在源源不断地产生设备日志、工艺配方参数、量测数据、缺陷检测图片、WIP追踪记录,甚至传感器采集的秒级时序数据。过去大家觉得这些数据“存下来总会有用”,…

2026/10/13 4:26:05 阅读更多 →
MySQL 5.7 Docker容器中文乱码根治:从字符集配置到编码转换全链路排查

MySQL 5.7 Docker容器中文乱码根治:从字符集配置到编码转换全链路排查

部署旧版本系统时,MySQL 5.7 在 Docker 容器里的乱码问题,我前前后后碰了不下十次。每次帮别人排查,症状都差不多:数据写进去是好的,读出来变"???",或者网页上显示"锟斤拷"&#xf…

2026/10/13 4:26:05 阅读更多 →
个人电脑安全体检:从系统配置到网络暴露面的全面评估指南

个人电脑安全体检:从系统配置到网络暴露面的全面评估指南

1. 为什么我们需要给个人电脑做“安全体检”干了这么多年系统维护和IT支持,我越来越觉得“安全状态检测与评估”这件事,像给车做年检一样。不是说你平时开着没毛病就不用管,也不是装了杀毒软件就万事大吉。个人电脑里的数据、账号、浏览记录、…

2026/10/13 4:26:05 阅读更多 →
DLT645-2007电表协议实战:报文解析与联调避坑指南

DLT645-2007电表协议实战:报文解析与联调避坑指南

简介:DL/T 645-2007《多功能电能表通信协议》最终版完整文档,由电力行业电测量标准化技术委员会归口发布,替代了1997年旧版,面向电能表研发、用电信息采集系统开发、计量运维及规约测试人员。文档系统规定了多功能电能表与数据采集…

2026/10/13 4:26:05 阅读更多 →
Linux内核链表实战:从自然数重排掌握list_head核心操作

Linux内核链表实战:从自然数重排掌握list_head核心操作

1. 从一道内核链表题说起:为什么值得认真拆解第一次看到“用链表存储若干自然数,把 1 2 3 4 5 6 7 8 9 重排成 1 3 5 7 9 8 6 4 2”这个题目时,很多人第一反应是“这不就是个数组排序题吗,开个数组分奇偶两半,奇数正着…

2026/10/13 4:26:05 阅读更多 →
年销460万辆同比增7.73%:新能源头部车企销量背后的结构密码

年销460万辆同比增7.73%:新能源头部车企销量背后的结构密码

开头,我直接说结论:2025年,某头部新能源车企全年销量突破460万辆,同比增速7.73%。这个数字放在整个行业里有多重?2024年这家企业的销量基数已经在400万辆以上,能在这样的体量上继续维持正增长,而…

2026/10/13 4:25:05 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →