[TOC]
内置序列类型概览
列表推导和生成器表达式
In [25]: [s for s in "string" if s != "i"]
Out[25]: [‘s‘, ‘t‘, ‘r‘, ‘n‘, ‘g‘]
In [27]: {s:i for i, s in enumerate("string")}
Out[27]: {‘g‘: 5, ‘i‘: 3, ‘n‘: 4, ‘r‘: 2, ‘s‘: 0, ‘t‘: 1}
In [28]: (s for s in "string" if s != "i")
Out[28]: <generator object <genexpr> at 0x7fd844195fc0>
In [29]: list(s for s in "string" if s != "i") # 这里只需要一个括号
Out[29]: [‘s‘, ‘t‘, ‘r‘, ‘n‘, ‘g‘]
元组
元组拆包
In [30]: a, b, *rest = range(5)
In [31]: a, b, *rest # rest均是一个list,无论有没有值
Out[31]: (0, 1, 2, 3, 4)
In [32]: a, b, *rest = range(3)
In [33]: a, b, *rest
Out[33]: (0, 1, 2)
In [34]: rest
Out[34]: [2]
In [35]: a, b, *rest = range(2)
In [36]: rest
Out[36]: []
具名元组
collections.namedtuple 是一个工厂函数,它可以用来构建一个带字段名的元组和一个有名字的类——这个带名字的类对调试程序有很大帮助。
In [1]: from collections import namedtuple
In [2]: City = namedtuple(‘City‘, ‘name coutry population coordinates‘)
In [3]: tokyo = City(‘Tokyo‘, ‘JP‘, 36.933, (35.689722, 139.691667))
In [4]: tokyo.name # 可以通过属性,以及索引来获取值.
Out[4]: ‘Tokyo‘
In [5]: tokyo["name"]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-b68fdbfa4b27> in <module>()
----> 1 tokyo["name"]
TypeError: tuple indices must be integers or slices, not str
In [6]: tokyo[1]
Out[6]: ‘JP‘
In [7]: City._fields # 包含这个类所有字段名称的元组
Out[7]: (‘name‘, ‘coutry‘, ‘population‘, ‘coordinates‘)
In [8]: LatLong = namedtuple(‘LatLong‘, ‘lat long‘)
In [9]: City = namedtuple(‘City‘, ‘name coutry population coordinates‘)
In [10]: delhi_data = (‘Delhi NCR‘, ‘IN‘, 21.935, LatLong(28.613889, 77.208889))
In [11]: delhi = City._make(delhi_data) # 接受一个可迭代对象来生成这个类的一个实例,等于City(*delhi_data)
In [12]: delhi._asdict() # 具名元组以 collections.OrderedDict 的形式返回
Out[12]:
OrderedDict([(‘name‘, ‘Delhi NCR‘),
(‘coutry‘, ‘IN‘),
(‘population‘, 21.935),
(‘coordinates‘, LatLong(lat=28.613889, long=77.208889))])
In [13]: for key, value in delhi._asdict().items():
...: print(key + ‘:‘, value)
...:
name: Delhi NCR
coutry: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
方法 | 列表 | 元组 | 说明 |
---|---|---|---|
s.__add__(s2) |
? | ? | s + s2,拼接 |
s.__iadd__(s2) |
? | s += s2,就地拼接 | |
s.append(e) |
? | 在尾部添加一个新元素 | |
s.clear() |
? | 删除所有元素 | |
s.__contains__(e) |
? | ? | s 是否包含 e |
s.copy() |
? | 列表的浅复制 | |
s.count(e) |
? | ? | e 在 s 中出现的次数 |
s.__delitem__(p) |
? | 把位于 p 的元素删除 | |
s.extend(it) |
? | 把可迭代对象 it 追加给 s | |
s.__getitem__(p) |
? | ? | s[p],获取位置 p 的元素 |
s.__getnewargs__() |
? | 在 pickle 中支持更加优化的序列化 | |
s.index(e) |
? | ? | 在 s 中找到元素 e 第一次出现的位置 |
s.insert(p, e) |
? | 在位置 p 之前插入元素e | |
s.__iter__() |
? | ? | 获取 s 的迭代器 |
s.__len__() |
? | ? | len(s),元素的数量 |
s.__mul__(n) |
? | ? | s * n, n 个 s 的重复拼接 |
s.__imul__(n) |
? | s *= n,就地重复拼接 | |
s.__rmul__(n) |
? | ? | n * s,反向拼接 * |
s.pop([p]) |
? | 删除最后或者是(可选的)位于 p 的元素,并返回它的值 | |
s.remove(e) |
? | 删除 s 中的第一次出现的 e | |
s.reverse() |
? | 就地把 s 的元素倒序排列 | |
s.__reversed__() |
? | 返回 s 的倒序迭代器 | |
s.__setitem__(p, e) |
? | s[p] = e,把元素 e放在位置p,替代已经在那个位置的元素 | |
s.sort([key],[reverse]) |
? | 就地对s中的元素进行排序,可选的参数有键(key)和是否倒序( reverse) |
对序列使用+和*
In [14]: board = [[‘_‘] * 3 for i in range(3)]
In [15]: board
Out[15]: [[‘_‘, ‘_‘, ‘_‘], [‘_‘, ‘_‘, ‘_‘], [‘_‘, ‘_‘, ‘_‘]]
In [16]: board[1][2]
Out[16]: ‘_‘
In [17]: board[1][2] = ‘X‘
In [18]: board
Out[18]: [[‘_‘, ‘_‘, ‘_‘], [‘_‘, ‘_‘, ‘X‘], [‘_‘, ‘_‘, ‘_‘]]
上面的代码等价于:
In [23]: def f():
...: board = []
...: for i in range(3):
...: row = [‘_‘] * 3
...: board.append(row)
而下面的代码会出现预想不到的结果:
In [19]: weird_board = [[‘_‘] * 3] * 3
In [20]: weird_board
Out[20]: [[‘_‘, ‘_‘, ‘_‘], [‘_‘, ‘_‘, ‘_‘], [‘_‘, ‘_‘, ‘_‘]]
In [21]: weird_board[1][2] = ‘X‘
In [22]: weird_board
Out[22]: [[‘_‘, ‘_‘, ‘X‘], [‘_‘, ‘_‘, ‘X‘], [‘_‘, ‘_‘, ‘X‘]]
等价于:
row=[‘_‘] * 3
board = []
for i in range(3):
board.append(row)
序列的增量赋值
变量名会不会被关联到新的对象,完全取决于这个类型有没有实现
__iadd__
这个方法.
什么意思?对于
a += b
- 如果 a 实现了
__iadd__
方法,就会调用这个方法。同时对可变序列(例如list、 bytearray 和 array.array)来说, a 会就地改动,就像调用了a.extend(b)
一样。 - 如果 a 没有实现
__iadd__
的话,a += b
这个表达式的效果就变得跟a = a+ b
一样了:首先计算 a + b,得到一个新的对象,然后赋值给 a。 - 也就是说,在这个表达式中,变量名会不会被关联到新的对象,完全取决于这个类型有没有实现
__iadd__
(类是的其他方法,__imul__
)这个方法。
对于元组里的可变列表进行+=操作
In [25]: t = (1, 2, [30, 40])
In [26]: t[2] += [50, 60]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-26-d877fb0e9d36> in <module>()
----> 1 t[2] += [50, 60]
TypeError: ‘tuple‘ object does not support item assignment
In [27]: t
Out[27]: (1, 2, [30, 40, 50, 60])
得到的结论是:
- 会改变
- 并且会抛出异常
- 增量赋值不是一个原子操作
list.sort方法和内置函数sorted
- list.sort 方法会就地排序列表,也就是说不会把原列表复制一份。这也是这个方法的返回值是 None 的原因,提醒你本方法不会新建一个列表。
- list.sort 相反的是内置函数 sorted,它会新建一个列表作为返回值。
两个可选的关键字参数
- reverse, True or False, default=False
- key, 对比关键字.
key=str.lower
来实现忽略大小写的排序,或者是用key=len
进行基于字符串长度的排序。
用bisect来管理已排序的序列
利用二分查找算法来在有序序列中查找或插入元素
import bisect
bisect.bisect(list, val)
bisect 函数其实是 bisect_right 函数的别名,后者还有个姊妹函数叫bisect_left。它们的区别在于, bisect_left 返回的插入位置是原序列中跟被插入元素相等的元素的位置,也就是新元素会被放置于它相等的元素的前面,而 bisect_right返回的则是跟它相等的元素之后的位置。
bisect.insort(seq, item)
把变量 item 插入到序列 seq 中
当列表不是首选时
array
>>> from array import array ?
>>> from random import random
>>> floats = array(‘d‘, (random() for i in range(10**7))) ?
>>> floats[-1] ?
0.07802343889111107
>>> fp = open(‘floats.bin‘, ‘wb‘)
>>> floats.tofile(fp) ?
>>> fp.close()
>>> floats2 = array(‘d‘) ?
>>> fp = open(‘floats.bin‘, ‘rb‘)
>>> floats2.fromfile(fp, 10**7) ?
>>> fp.close()
>>> floats2[-1] ?
0.07802343889111107
>>> floats2 == floats
True
方法 | 列表 | 数组 | 说明 |
---|
|s.__add(s2)__
|? |?| s + s2,拼接|
|s.__iadd(s2)__
|? |?| s += s2,就地拼接|
|s.append(e)| ?| ?| 在尾部添加一个元素|
|s.byteswap| |?| 翻转数组内每个元素的字节序列,转换字节序|
|s.clear()| ?| |删除所有元素|
|s.__contains__(e)
| ? |?| s 是否含有 e|
|s.copy()| ?| |对列表浅复制|
|s.__copy__()
|?| |对 copy.copy 的支持|
|s.count(e)| ?| ?| s 中 e 出现的次数|
|s.__deepcopy__()
| |?| 对 copy.deepcopy 的支持|
|s.__delitem__(p)
| ?| ? |删除位置 p 的元素|
|s.extend(it)| ? |? |将可迭代对象 it 里的元素添加到尾部|
|s.frombytes(b)| |?| 将压缩成机器值的字节序列读出来添加到尾部|
|s.fromfile(f, n)| |?| 将二进制文件 f 内含有机器值读出来添加到尾部,最多添加 n 项|
|s.fromlist(l)| |?| 将列表里的元素添加到尾部,如果其中任何一个元素导致了 TypeError异常,那么所有的添加都会取消|
|s.__getitem__(p)
| ?| ?| s[p],读取位置 p 的元素|
|s.index(e)| ?| ? |找到 e 在序列中第一次出现的位置|
|s.insert(p, e) |? |? |在位于 p 的元素之前插入元素 e|
|s.itemsize| |? |数组中每个元素的长度是几个字节|
|s.__iter__()
|?| ?| 返回迭代器|
|s.__len__()
|?| ?| len(s),序列的长度|
|s.__mul__(n)
|? |?| s * n,重复拼接|
|s.__imul__(n)
|? |?| s = n,就地重复拼接|
|s.__rmul__(n)
|?| ?| n s,反向重复拼接*|
|s.pop([p])| ? |? |删除位于 p 的值并返回这个值, p 的默认值是最后一个元素的位置|
|s.remove(e) |? |?| 删除序列里第一次出现的 e 元素|
|s.reverse() |? |?| 就地调转序列中元素的位置|
|s.__reversed__()
|?| |返回一个从尾部开始扫描元素的迭代器|
|s.__setitem__(p,e)
| ?| ? |s[p] = e,把位于 p 位置的元素替换成 e|
|s.sort([key],[revers])| ?| |就地排序序列,可选参数有 key 和 reverse|
|s.tobytes()| |?| 把所有元素的机器值用 bytes 对象的形式返回|
|s.tofile(f)| |?| 把所有元素以机器值的形式写入一个文件|
|s.tolist()| |?| 把数组转换成列表,列表里的元素类型是数字对象|
|s.typecode| |?| 返回只有一个字符的字符串,代表数组元素在 C 语言中的类型|
内存视图
memoryview 是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切片。 这个功能在处理大型数据集合的时候非常重要。
>>> numbers = array.array(‘h‘, [-2, -1, 0, 1, 2])
>>> memv = memoryview(numbers) ?
>>> len(memv)
5
>>> memv[0] ?
-2
>>> memv_oct = memv.cast(‘B‘) ?
>>> memv_oct.tolist() ?
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
>>> memv_oct[5] = 4 ?
>>> numbers
array(‘h‘, [-2, -1, 1024, 1, 2])
双向队列和其他形式的队列
但是删除列表的第一个元素(抑或是在第一个元素之前添加一个元素)之类的操作是很耗时的,因为这些操作会牵扯到移动列表里的所有元素。
collections.deque 类(双向队列)是一个线程安全、可以快速从两端添加或者删除元素的数据类型。
>>> from collections import deque
>>> dq = deque(range(10), maxlen=10) ?
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3) ?
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1) ?
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11, 22, 33]) ?
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10, 20, 30, 40]) ?
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
方法 | 列表 | 双向队列 | 说明 |
---|---|---|---|
s.__add__(s2) |
? | s + s2,拼接 | |
s.__iadd__(s2) |
? | ? s += s2,就地拼接 | |
s.append(e) | ? | ? | 添加一个元素到最右侧(到最后一个元素之后) |
s.appendleft(e) | ? | 添加一个元素到最左侧(到第一个元素之前) | |
s.clear() | ? | ? | 删除所有元素 |
s.__contains__(e) |
? | s 是否含有 e | |
s.copy() | ? | 对列表浅复制 | |
s.__copy__() |
? | 对 copy.copy(浅复制)的支持 | |
s.count(e) | ? | ? | s 中 e 出现的次数 |
s.__delitem__(p) |
? | ? | 把位置 p 的元素移除 |
s.extend(i) | ? | ? | 将可迭代对象 i 中的元素添加到尾部 |
s.extendleft(i) | ? | 将可迭代对象 i 中的元素添加到头部 | |
s.__getitem__(p) |
? | ? | s[p],读取位置 p 的元素 |
s.index(e) | ? | 找到 e 在序列中第一次出现的位置 | |
s.insert(p, e) | ? | 在位于 p 的元素之前插入元素 e | |
s.__iter__() |
? | ? | 返回迭代器 |
s.__len__() |
? | ? | len(s),序列的长度 |
s.__mul__(n) |
? | s * n,重复拼接 | |
s.__imul__(n) |
? | s *= n,就地重复拼接 | |
s.__rmul__(n) |
? | n * s,反向重复拼接* | |
s.pop() | ? | ? | 移除最后一个元素并返回它的值# |
s.popleft() | ? | 移除第一个元素并返回它的值 | |
s.remove(e) | ? | ? | 移除序列里第一次出现的 e 元素 |
s.reverse() | ? | ? | 调转序列中元素的位置 |
s.__reversed__() |
? | ? | 返回一个从尾部开始扫描元素的迭代器 |
s.rotate(n) | ? | 把 n 个元素从队列的一端移到另一端 | |
s.__setitem__(p, e) |
? | ? s | [p] = e,把位于 p 位置的元素替换成 e |
s.sort([key], [revers]) | ? | 就地排序序列,可选参数有 key 和 reverse |
其他的队列有空在总结.