Python 高级编程 026:序列内核深剖
- 📖 前言
- Bilibili 同步视频
- 🌌 一、双维剖序列:分容器与扁平,辨可变与不可变
- 1.1 第一维度:按存储元素划分「容器序列 & 扁平序列」
- ✅ 容器序列:包罗万象,兼容任意数据类型
- ✅ 扁平序列:恪守本源,仅存同源基础数据
- 1.2 第二维度:按修改权限划分「可变序列 & 不可变序列」
- ⚙️ 二、溯源序列协议:剖析抽象基类继承脉络
- 2.1 不可变序列 Sequence 继承链路
- 四大底层基类各司其职,一一拆解:
- 🔥 Python底层优化冷知识(高频面试考点)
- 2.2 可变序列 MutableSequence 能力拓展
- 🚀 三、四大序列拼接操作:辨异同、明底层、测性能
- 3.1 加法运算符 +:新址拼接,另起炉灶
- 3.2 增量赋值 +=:原地叠加,复用内存
- 3.3 extend方法:迭代拆解,逐元并入
- 3.4 append方法:整体入列,不拆元素
- 3.5 四大方法直观对照代码+性能测速
- 📊 测速结论(硬核心性能数据):
- 📝 全文总结:一文通晓序列全部核心要点
- 🔮 下期预告
📖 前言
Python之道,循协议而行;万物之象,依规约而生。
不同于静态语言固化的数据结构,Python奉行协议编程思想,无严苛的类继承枷锁,只要补齐对应魔法方法,便可拥有对应数据结构的能力。
而序列,乃是Python万物容器之中流砥柱🌊。字符串、列表、元组、数组,皆归序列麾下;循环遍历、下标取值、成员判断,皆赖序列赋能。
很多开发者终日使用列表与字符串,却不知序列底层协议为何,分不清+、+=、append、extend本质差异,日常编码暗藏内存冗余、性能损耗隐患。
本文以骈文行文,深入浅出拆解Python序列全貌:
二分维度,厘清序列品类之别📊
溯源抽象基类,吃透序列底层协议⚙️
拆解四大拼接操作,深挖底层魔法函数+内存性能差异🚀
附全套可运行实测代码,零基础亦可一键复现✅
Bilibili 同步视频
Python 高级编程 026:序列内核深剖
🌌 一、双维剖序列:分容器与扁平,辨可变与不可变
序列品类,二分而立;一横存数类型,一纵改值权限。纵横相交,囊括Python全部内置序列类型,泾渭分明,分毫不错。
1.1 第一维度:按存储元素划分「容器序列 & 扁平序列」
容器序列者,海纳百川,无拘元素类型;
扁平序列者,守一而终,仅限同类元素。
二者核心鸿沟,在于元素存储自由度,下文附实测代码直观佐证👇
✅ 容器序列:包罗万象,兼容任意数据类型
涵盖三类内置结构:list列表、tuple元组、deque双端队列。
如同万能收纳箱,整型、字符串、列表、对象,皆可同箱共存,无需统一元素格式。
# 容器序列实测代码:多类型元素共存无报错my_list=[1,"Python序列",3.14,[1,2,3]]print(my_list)# 输出:[1, 'Python序列', 3.14, [1, 2, 3]]# 结论:列表作为典型容器序列,完全支持异构元素存储✅ 扁平序列:恪守本源,仅存同源基础数据
涵盖四类内置结构:str字符串、bytes字节串、bytearray可变字节数组、array.array数值数组。
如同专用储物格,一格一类,不可混杂。其中array.array极易与列表混淆:列表动态包容万物,数组初始化必须指定固定数据类型,运行期间不可更改元素格式,内存占用远低于列表,数值计算性能更优。
importarray# 扁平序列array实测:初始化强制指定元素类型arr=array.array("i",[1,2,3,4])# i代表整型数组,仅能存放整数# arr.append("abc") # 放开注释直接报错,无法存入字符串异构元素print(arr)1.2 第二维度:按修改权限划分「可变序列 & 不可变序列」
可变序列者,就地更迭,改值不换内存地址;
不可变序列者,一成永固,改值必建新内存。
| 序列分类 | 包含类型 | 底层特性 | 适用场景 |
|---|---|---|---|
| 🔄 可变序列 | list、deque、bytearray、array.array | 原地增删改,无新对象生成,内存开销小 | 频繁变更数据、海量数据存储 |
| 🛡️ 不可变序列 | tuple、str、bytes | 创建后只读,修改必定生成新对象,线程安全 | 常量存储、字典键值、防止数据误修改 |
核心小结:所有序列皆可for循环遍历、支持下标取值;二分维度相互独立,例如列表既是容器序列,亦是可变序列;元组既是容器序列,亦是不可变序列。
⚙️ 二、溯源序列协议:剖析抽象基类继承脉络
知其表象,更要知其内核。Python一切序列,皆遵循统一协议规约,协议本质就是必须实现的魔法方法合集。
Python通过collections.abc内置抽象基类,明文定义序列协议,分为两大核心父类:
Sequence:不可变序列基类,序列协议之根基
MutableSequence:可变序列基类,继承Sequence并拓展修改能力
2.1 不可变序列 Sequence 继承链路
Sequence 双层继承,四层底层能力支撑序列全部基础功能:
Sequence → Reversible + Collection
Collection → Sized + Iterable + Container
四大底层基类各司其职,一一拆解:
Sized(长度协议):实现
__len__魔法方法,支持全局函数len()获取容器长度Iterable(迭代协议):实现迭代器接口,支撑for循环全程遍历
Container(成员协议):实现
__contains__魔法方法,支撑x in 序列成员判断Reversible(反转协议):实现反转接口,支撑
reversed()反转遍历序列
🔥 Python底层优化冷知识(高频面试考点)
执行value in obj判断时,解释器存在优先级适配:
优先调用__contains__方法;若无该方法,自动降级调用__getitem__下标取值方法,逐一遍历匹配,保证代码向下兼容。
2.2 可变序列 MutableSequence 能力拓展
可变序列立于不可变序列之上,新增三大核心修改类魔法方法,赋能原地增删改:
__setitem__:下标赋值,对应obj[0] = 100__delitem__:下标删除,对应del obj[0]__iadd__:增量拼接,对应+=运算符底层实现
同时原生内置封装好的高频方法:append、extend、pop、clear、remove,无需开发者手动实现底层逻辑。
自定义序列核心准则:想要自研专属序列类,只需继承对应抽象基类,并且补齐所有抽象魔法方法,即可完全契合Python原生序列协议,无缝适配Python全部内置语法。
🚀 三、四大序列拼接操作:辨异同、明底层、测性能
日常编码之中,+、+=、append、extend四法常被混用,看似结果相近,实则内存机制、底层调用、入参规则、运行性能天差地别。
下文骈文释义+底层源码逻辑+实测代码+性能对比,一次性彻底讲透👇
3.1 加法运算符 +:新址拼接,另起炉灶
两列相加,新内存而生;原列不变,旧地址长存。
底层魔法方法:
__add__内存逻辑:不修改原有两个序列,直接开辟全新内存空间,生成新序列对象
入参限制:严苛强制,仅支持同类型序列拼接,列表无法直接加元组
性能短板:海量数据拼接时,频繁创建新对象,内存碎片激增,效率极低
a=[1,2]# + 生成全新列表,原列表a无任何变化c=a+[3,4]print(a)# [1,2] 原值不变print(c)# [1,2,3,4] 新对象# 报错演示:列表+元组类型不匹配# res = a + (5,6) # TypeError: can only concatenate list (not "tuple") to list3.2 增量赋值 +=:原地叠加,复用内存
就地增补,不辟新址;兼容万物,迭代入列。
底层魔法方法:
__iadd__,内部直接调用extend方法内存逻辑:原地修改原序列,不生成新对象,内存零额外开销
入参限制:极度宽松,支持任意可迭代对象(元组、range、生成器、字符串均可)
性能优势:无内存拷贝,大数据拼接性能碾压+运算符
a=[1,2]a+=(3,4)# 支持元组a+=range(2)# 支持range可迭代对象print(a)# [1,2,3,4,0,1]3.3 extend方法:迭代拆解,逐元并入
遍历迭代,拆解元素;逐一追加,平铺入列。
底层逻辑:遍历传入可迭代对象,拆分每一个元素,逐个追加至原列表
返回值:无返回值,纯原地修改
适用场景:需要将容器内部元素平铺合并,而非嵌套容器
3.4 append方法:整体入列,不拆元素
整体收纳,不拆分毫;嵌套生成,初心不改。
底层逻辑:直接将传入参数作为单个独立元素存入列表,不做任何迭代拆分
高频误区:初学者经常混淆append与extend,导致意外嵌套列表BUG
3.5 四大方法直观对照代码+性能测速
importtime# 1. append整体添加lst1=[1,2]lst1.append([3,4])print("append结果:",lst1)# [1,2,[3,4]] 嵌套列表# 2. extend拆分添加lst2=[1,2]lst2.extend([3,4])print("extend结果:",lst2)# [1,2,3,4] 平铺列表# 性能测速:10万次拼接耗时对比t1=time.time()a=[]foriinrange(100000):a=a+[i]print("+拼接耗时:",time.time()-t1)t2=time.time()a=[]foriinrange(100000):a+=[i]print("+=拼接耗时:",time.time()-t2)📊 测速结论(硬核心性能数据):
+耗时远超+=,大数据场景下**+=/extend性能是+的百倍以上**,开发中严禁循环内使用+拼接序列。
📝 全文总结:一文通晓序列全部核心要点
行文至此,以骈句总括全文,铭记序列精髓:
序列二分,横竖有别;容器纳异,扁平存同。
可变就地改,不可建新容;协议藏基类,魔法驭行踪。
加号建新址,+=复用踪;extend拆元素,append纳全宗。
序列分两类维度:存储类型、修改权限,精准区分所有内置序列
序列协议依托abc抽象基类,四大底层协议支撑遍历、长度、成员判断能力
循环拼接优先使用
+=与extend,拒绝+,规避内存爆炸问题需要平铺元素选extend,需要嵌套整体元素选append,杜绝业务BUG
🔮 下期预告
下一篇将手把手从零手写自定义可切片序列类,完整实现序列全部魔法方法,真正吃透Python协议编程精髓,敬请关注✨
💬 写在最后:技术不止代码逻辑,更有底层原理。知其然亦知其所以然,方能写出更Pythonic、更高性能、更少BUG的优质代码❤️