这篇文章我们会了解到Python的序列协议是什么,以及通过序列协议使类或者实例转变为序列。
Python中的内置序列分类
我们按照两个维度来区分序列
第一个维度是按照序列存贮的数据类型,分为容器序列和扁平序列
1 | 容器序列 |
1 | 扁平序列 |
容器序列里面可以放任意类型的数据。扁平序列的数据类型一致。
注意:array和list的一个重要区别, array只能存放指定的数据类型
第二个维度是按照序列是否可变,分为可变序列和不可变序列
1 | 可变序列 |
1 | 不可变 |
Python中序列类型的abc继承关系
这一小节我们将通过abc继承关系来讲下序列协议
跟容器相关的数据结构的抽象基类都存在_collections_abc.py
模块下。
1 | "Sequence"(不可变序列), "MutableSequence"(可变序列), |
我们看下不可变序列(Sequence)的源码是由哪些抽象函数协议组成的。
1 | class Sequence(Reversible, Collection): |
Sequence继承了Reversible(用于翻转)和Collection。
我们再看看Collection的源码。
1 | class Collection(Sized, Iterable, Container): |
Collection 又分别继承Sized, Iterable, Container。我们看下这三个类的源码
1 | class Sized(metaclass=ABCMeta): |
Sized实现了__len__
使我们的序列具有长度。
1 | class Iterable(metaclass=ABCMeta): |
Iterable实现了__iter__
使我们的序列可以迭代(for 操作)
1 | class Container(metaclass=ABCMeta): |
Container实现了__contains__
使我们可以使用 is in 判断是否存在序列中。
通过上述的魔法函数组成了构成不可变序列的协议。
对于可变序列MutableSequence,作为不可变序列Sequence的子类,我们看看它的源码多实现了哪些魔法函数。
1 | class MutableSequence(Sequence): |
我们看到最主要的是新增了__setitem__
用于赋值,__delitem__
用于删除值。这两个魔法函数。
如果我们想自定义一些序列类,只需要实现上述魔法函数(协议)即可。
序列的+、+=和extend的区别
我们看下下面代码
1 | a = [1, 2] |
对于 +
两边的数据类型必须一致,而 +=
只需要是序列类型即可。
为什么 +=
只要是序列就可以呢?
我们看看+=
的实现源码:
1 | class MutableSequence(Sequence): |
在可变序列MutableSequence中的__iadd__
就是实现 +=
操作的,我们看到中间有调用
extend,我们看看extend函数有要求的是可迭代类型。
对于extend:
1 |
|
我们看到extend内置源码实现原理接收一个可迭代对象。
实现可切片的对象
下面是Python序列切片使用
1 | # 模式[start:end:step] |
下面是自定义一个不可变得序列类
1 | import numbers |
bisect维护已排序序列
注意:一定要是一个已排序的序列
我们先看下这个模块的源码结构
其中的insort
为插入数据是insort_right
的缩写,bisect
为查询插入位置是bisect_right
的缩写。
1 | In [11]: import bisect |
看一篇bisect的妙用文章:Python-bisect模块的妙用
什么时候不该使用列表
有时对于使用list对性能有很大影响或者,我们可以考虑使用其他序列如array, deque。
1 | import array |
array支持的数据类型查看 array