📖 前言
Python之道,循协议而行;万物之象,依规约而生。
不同于静态语言固化的数据结构,Python奉行协议编程思想,无严苛的类继承枷锁,只要补齐对应魔法方法,便可拥有对应数据结构的能力。
而序列,乃是Python万物容器之中流砥柱🌊。字符串、列表、元组、数组,皆归序列麾下;循环遍历、下标取值、成员判断,皆赖序列赋能。
很多开发者终日使用列表与字符串,却不知序列底层协议为何,分不清+、+=、append、extend本质差异,日常编码暗藏内存冗余、性能损耗隐患。
本文以骈文行文,深入浅出拆解Python序列全貌:
-
二分维度,厘清序列品类之别📊
-
溯源抽象基类,吃透序列底层协议⚙️
-
拆解四大拼接操作,深挖底层魔法函数+内存性能差异🚀
-
附全套可运行实测代码,零基础亦可一键复现✅
Bilibili 同步视频
🌌 一、双维剖序列:分容器与扁平,辨可变与不可变
序列品类,二分而立;一横存数类型,一纵改值权限。纵横相交,囊括Python全部内置序列类型,泾渭分明,分毫不错。
1.1 第一维度:按存储元素划分「容器序列 & 扁平序列」
容器序列者,海纳百川,无拘元素类型;
扁平序列者,守一而终,仅限同类元素。
二者核心鸿沟,在于元素存储自由度,下文附实测代码直观佐证👇
✅ 容器序列:包罗万象,兼容任意数据类型
涵盖三类内置结构:list列表、tuple元组、deque双端队列。
如同万能收纳箱,整型、字符串、列表、对象,皆可同箱共存,无需统一元素格式。
python
# 容器序列实测代码:多类型元素共存无报错
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极易与列表混淆:列表动态包容万物,数组初始化必须指定固定数据类型,运行期间不可更改元素格式,内存占用远低于列表,数值计算性能更优。
python
import array
# 扁平序列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__ -
内存逻辑:不修改原有两个序列,直接开辟全新内存空间,生成新序列对象
-
入参限制:严苛强制,仅支持同类型序列拼接,列表无法直接加元组
-
性能短板:海量数据拼接时,频繁创建新对象,内存碎片激增,效率极低
python
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 list
3.2 增量赋值 +=:原地叠加,复用内存
就地增补,不辟新址;兼容万物,迭代入列。
-
底层魔法方法:
__iadd__,内部直接调用extend方法 -
内存逻辑:原地修改原序列,不生成新对象,内存零额外开销
-
入参限制:极度宽松,支持任意可迭代对象(元组、range、生成器、字符串均可)
-
性能优势:无内存拷贝,大数据拼接性能碾压+运算符
python
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 四大方法直观对照代码+性能测速
python
import time
# 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 = []
for i in range(100000):
a = a + [i]
print("+拼接耗时:", time.time()-t1)
t2 = time.time()
a = []
for i in range(100000):
a += [i]
print("+=拼接耗时:", time.time()-t2)
📊 测速结论(硬核心性能数据):
+ 耗时远超 +=,大数据场景下**+=/extend性能是+的百倍以上**,开发中严禁循环内使用+拼接序列。
📝 全文总结:一文通晓序列全部核心要点
行文至此,以骈句总括全文,铭记序列精髓:
序列二分,横竖有别;容器纳异,扁平存同。
可变就地改,不可建新容;协议藏基类,魔法驭行踪。
加号建新址,+=复用踪;extend拆元素,append纳全宗。
-
序列分两类维度:存储类型、修改权限,精准区分所有内置序列
-
序列协议依托abc抽象基类,四大底层协议支撑遍历、长度、成员判断能力
-
循环拼接优先使用
+=与extend,拒绝+,规避内存爆炸问题 -
需要平铺元素选extend,需要嵌套整体元素选append,杜绝业务BUG
🔮 下期预告
下一篇将手把手从零手写自定义可切片序列类,完整实现序列全部魔法方法,真正吃透Python协议编程精髓,敬请关注✨

💬 写在最后:技术不止代码逻辑,更有底层原理。知其然亦知其所以然,方能写出更Pythonic、更高性能、更少BUG的优质代码❤️