目录:
本篇主要讲序列的通用操作,如切片,运算符。以及序列的排序,搜索。还有一些遇到性能瓶颈时,用于取代 list 的数据结构。
切片(Slice)
切片是序列中非常常用的操作,基本格式是 seq[start:stop:step],其中step及之前的冒号均可以省略,表示 step 为1。start和stop也都可以省略,但是第一个冒号不能省略。start省略表示从头开始,stop省略表示切到尾部。
切片操作适用于几乎所有序列类型,如 list, tuple, str 等等。
示例:
>>> l = [10, 20, 30, 40, 50, 60]
>>> l[:2] # split at 2
[10, 20]
>>> l[2:]
[30, 40, 50, 60]
>>> l[2:4]
[30, 40]
Python 中表示范围一般使用前闭后开 [start, stop),根据这两个单词也比较容易记忆。
切片的长度,自然也就是 stop - start。
切片对象:
符号 a:b:c 只有在 [] 中作为索引使用时才有意义,产生了一个切片对象:slice(a, b, c)。
在计算 seq[start:stop:step]时,Python 调用 seq.__getitem__(slice(start, stop, step))。
切片对象是可以命名的(实际上 Python 中的赋值都是把名称绑定到对象上):
>>> MIDDLE = slice(2:4)
>>> l[MIDDLE]
[30, 40]
多维切片:
很少会用到,但需要记住的是:
计算 a[i, j] 时,Python 调用 a.__getitem__((i, j))。
切片赋值:
我们可以把可变序列中的某个条目替换为其他值,当然也可以把其中的一个切片对应的部分替换为另一个序列,长度可以不同。也可以把这部分删除。
示例:
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[2:5] = [20, 30]
>>> l
[0, 1, 20, 30, 5, 6, 7, 8, 9]
>>> del l[5:7]
>>> l
[0, 1, 20, 30, 5, 8, 9]
>>> l[3::2] = [11, 22]
>>> l
[0, 1, 20, 11, 5, 22, 9]
>>> l[2:5] = 100
Traceback (most recent call last):
File "", line 1, in
TypeError: can only assign an iterable
>>> l[2:5] = [100]
>>> l
[0, 1, 100, 22, 9]
需要注意:不可变序列不能这样赋值。(这是很显然的)
给切片赋值的时候,只能用序列。(不能用单个条目)
序列的运算符操作
加法示例:
>>> [1, 2] + [3, 4, 5]
[1, 2, 3, 4, 5]
加号两边的序列类型必须相同。
乘法示例:
>>> l = [1, 2, 3]
>>> l * 5
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 5 * 'abcd'
'abcdabcdabcdabcdabcd'
加法和乘法都是创建一个新的序列,之前的序列都不会修改。
复合赋值:
在执行 += 的时候, Python 会首先检查 __iadd__ 函数有没有实现,如果没有,则 fall back 到 __add__ 。
执行 a += b 后,对于可变序列,a 的地址不会改变,对于不可变序列,a 的地址会改变。
排序
对于 list 来说,有两种排序方式:list.sort
对一个 list 就地排序,并返回 None 来提醒我们没有创建新的 list
(这是一个重要的 API 惯例:就地改变对象的函数和方法应该返回 None,从而明确地告诉调用者对象本身改变了,而不是创建了新的对象)
示例:
>>> fruits = ['grape', 'raspberry', 'apple', 'banana']
>>> fruits.sort()
>>> fruits
['apple', 'banana', 'grape', 'raspberry']sorted 函数
应用于一个列表上,并产生一个新的,已排序的列表,不改变之前的列表。
管理有序序列
在经过上面的方式排序以后,常用的操作有查找和插入。
这两个操作都使用 bisect 模块。使用 bisect.bisect_left 和 bisect.bisect_right 进行搜索
这两个函数都可以在一个有序序列中搜索 target。使用 bisect.insort 进行插入操作
排序是比较昂贵的操作,如果已经有了排好序的序列,可以用这个函数保持有序。
(这两个函数具体使用的时候查阅文档,常用的话就记住,不常用就了解下好了)
什么时候不该使用 list ?
由于 list 是一个非常方便的结构,写程序时不由自主就会首先考虑它,大部分情况下是没什么问题的,然而如果遇到了性能瓶颈,就需要考虑使用其他数据结构来替代 list。如果存的全是数字,那么使用 array.array
如果需要大量操作数字,请使用 memoryview。
如果还不够,请使用科学计算库 NumPy 和 SciPy。如果经常从两端添加删除元素,请使用 collections.deque
deque 是一个线程安全的双端队列,设计用来快速从两端插入删除。
可以设定最大长度,插入的时候如果超出了最大长度,就从对面忽略元素。
deque 实现了大部分 list 的方法,并添加了一些如 popleft 和 rotate。
append 和 popleft 都是原子操作,所以 deque 作为 LIFO 队列在多线程应用中是安全的,不需要加锁。如果有大量的包含检测(if item in my_collection),使用集合更好,集合为包含检测做了优化,保证极高的速度进行成员检测,当然,需要注意的是集合是无序的。