目录
通用序列操作
不可变序列类型
可变序列类型
列表
元组
range 对象
有三种基本序列类型:list, tuple 和 range 对象。 为处理 二进制数据 和 文本字符串 而特别定制的附加序列类型会在专门的小节中描述。
通用序列操作
大多数序列类型,包括可变类型和不可变类型都支持下表中的操作。 collections.abc.Sequence ABC 被提供用来更容易地在自定义序列类型上正确地实现这些操作。
此表按优先级升序列出了序列操作。 在表格中,s 和 t 是具有相同类型的序列,n, i, j 和 k 是整数而 x 是任何满足 s 所规定的类型和值限制的任意对象。
in
和 not in
操作具有与比较操作相同的优先级。 +
(拼接) 和 *
(重复) 操作具有与对应数值运算相同的优先级。 3
运算 | 结果: | 备注 |
---|---|---|
| 如果 s 中的某项等于 x 则结果为 | (1) |
| 如果 s 中的某项等于 x 则结果为 | (1) |
| s 与 t 相拼接 | (6)(7) |
| 相当于 s 与自身进行 n 次拼接 | (2)(7) |
| s 的第 i 项,起始为 0 | (3) |
| s 从 i 到 j 的切片 | (3)(4) |
| s 从 i 到 j 步长为 k 的切片 | (3)(5) |
| s 的长度 | |
| s 的最小项 | |
| s 的最大项 | |
| x 在 s 中首次出现项的索引号(索引号在 i 或其后且在 j 之前) | (8) |
| x 在 s 中出现的总次数 |
相同类型的序列也支持比较。 特别地,tuple 和 list 的比较是通过比较对应元素的字典顺序。 这意味着想要比较结果相等,则每个元素比较结果都必须相等,并且两个序列长度必须相同。 (完整细节请参阅语言参考的 比较运算 部分。)
可变序列的正向和逆向迭代器使用一个索引来访问值。 即使底层序列被改变该索引也将持续向前(或向后)步进。 迭代器只有在遇到 IndexError 或 a StopIteration 时才会终结(或是当索引降至零以下)。
注释:
-
虽然
>>>in
和not in
操作在通常情况下仅被用于简单的成员检测,某些专门化序列 (例如 str, bytes 和 bytearray) 也使用它们进行子序列检测:>>> "gg" in "eggs" True
-
小于
>>>0
的 n 值会被当作0
来处理 (生成一个与 s 同类型的空序列)。 请注意序列 s 中的项并不会被拷贝;它们会被多次引用。 这一点经常会令 Python 编程新手感到困扰;例如:>>> lists = [[]] * 3 >>> lists [[], [], []] >>> lists[0].append(3) >>> lists [[3], [3], [3]]
具体的原因在于
>>>[[]]
是一个包含了一个空列表的单元素列表,所以[[]] * 3
结果中的三个元素都是对这一个空列表的引用。 修改lists
中的任何一个元素实际上都是对这一个空列表的修改。 你可以用以下方式创建以不同列表为元素的列表:>>> lists = [[] for i in range(3)] >>> lists[0].append(3) >>> lists[1].append(5) >>> lists[2].append(7) >>> lists [[3], [5], [7]]
进一步的解释可以在 FAQ 条目 如何创建多维列表? 中查看。
-
如果 i 或 j 为负值,则索引顺序是相对于序列 s 的末尾: 索引号会被替换为
len(s) + i
或len(s) + j
。 但要注意-0
仍然为0
。 -
s 从 i 到 j 的切片被定义为所有满足
i <= k < j
的索引号 k 的项组成的序列。 如果 i 或 j 大于len(s)
,则使用len(s)
。 如果 i 被省略或为None
,则使用0
。 如果 j 被省略或为None
,则使用len(s)
。 如果 i 大于等于 j,则切片为空。 -
s 从 i 到 j 步长为 k 的切片被定义为所有满足
0 <= n < (j-i)/k
的索引号x = i + n*k
的项组成的序列。 换句话说,索引号为i
,i+k
,i+2*k
,i+3*k
,以此类推,当达到 j 时停止 (但一定不包括 j)。 当 k 为正值时,i 和 j 会被减至不大于len(s)
。 当 k 为负值时,i 和 j 会被减至不大于len(s) - 1
。 如果 i 或 j 被省略或为None
,它们会成为“终止”值 (是哪一端的终止值则取决于 k 的符号)。 请注意,k 不可为零。 如果 k 为None
,则当作1
处理。 -
拼接不可变序列总是会生成新的对象。 这意味着通过重复拼接来构建序列的运行时开销将会基于序列总长度的乘方。 想要获得线性的运行时开销,你必须改用下列替代方案之一:
-
如果拼接 str 对象,你可以构建一个列表并在最后使用 str.join() 或是写入一个 io.StringIO 实例并在结束时获取它的值
-
如果拼接 bytes 对象,你可以类似地使用 bytes.join() 或 io.BytesIO,或者你也可以使用 bytearray 对象进行原地拼接。 bytearray 对象是可变的,并且具有高效的重分配机制
-
如果拼接 tuple 对象,请改为扩展 list 类
-
对于其它类型,请查看相应的文档
-
-
某些序列类型 (例如 range) 仅支持遵循特定模式的项序列,因此并不支持序列拼接或重复。
-
当 x 在 s 中找不到时
index
会引发 ValueError。 不是所有实现都支持传入额外参数 i 和 j。 这两个参数允许高效地搜索序列的子序列。 传入这两个额外参数大致相当于使用s[i:j].index(x)
,但是不会复制任何数据,并且返回的索引是相对于序列的开头而非切片的开头。
不可变序列类型
不可变序列类型普遍实现而可变序列类型未实现的唯一操作就是对 hash() 内置函数的支持。
这种支持允许不可变类型,例如 tuple 实例被用作 dict 键,以及存储在 set 和 frozenset 实例中。
尝试对包含有不可哈希值的不可变序列进行哈希运算将会导致 TypeError。
可变序列类型
以下表格中的操作是在可变序列类型上定义的。 collections.abc.MutableSequence ABC 被提供用来更容易地在自定义序列类型上正确实现这些操作。
表格中的 s 是可变序列类型的实例,t 是任意可迭代对象,而 x 是符合对 s 所规定类型与值限制的任何对象 (例如,bytearray 仅接受满足 0 <= x <= 255
值限制的整数)。
运算 | 结果: | 备注 |
---|---|---|
| 将 s 的第 i 项替换为 x | |
| 将 s 从 i 到 j 的切片替换为可迭代对象 t 的内容 | |
| 等同于 | |
| 将 | (1) |
| 从列表中移除 | |
| 将 x 添加到序列的末尾 (等同于 | |
| 从 s 中移除所有项 (等同于 | (5) |
| 创建 s 的浅拷贝 (等同于 | (5) |
| 用 t 的内容扩展 s (基本上等同于 | |
| 使用 s 的内容重复 n 次来对其进行更新 | (6) |
| 在由 i 给出的索引位置将 x 插入 s (等同于 | |
| 提取在 i 位置上的项,并将其从 s 中移除 | (2) |
| 删除 s 中第一个 | (3) |
| 就地将列表中的元素逆序。 | (4) |
注释:
-
t 必须与它所替换的切片具有相同的长度。
-
可选参数 i 默认为
-1
,因此在默认情况下会移除并返回最后一项。 -
当在 s 中找不到 x 时
remove()
操作会引发 ValueError。 -
当反转大尺寸序列时
reverse()
方法会原地修改该序列以保证空间经济性。 为提醒用户此操作是通过间接影响进行的,它并不会返回反转后的序列。 -
包括
clear()
和copy()
是为了与不支持切片操作的可变容器 (例如 dict 和 set) 的接口保持一致。copy()
不是 collections.abc.MutableSequence ABC 的一部分,但大多数具体的可变序列类都提供了它。3.3 新版功能:
clear()
和copy()
方法。 -
n 值为一个整数,或是一个实现了 __index__() 的对象。 n 值为零或负数将清空序列。 序列中的项不会被拷贝;它们会被多次引用,正如 通用序列操作 中有关
s * n
的说明。
列表
列表是可变序列,通常用于存放同类项目的集合(其中精确的相似程度将根据应用而变化)。
class list([iterable])
可以用多种方式构建列表:
-
使用一对方括号来表示空列表:
[]
-
使用方括号,其中的项以逗号分隔:
[a]
,[a, b, c]
-
使用列表推导式:
[x for x in iterable]
-
使用类型的构造器:
list()
或list(iterable)
构造器将构造一个列表,其中的项与 iterable 中的项具有相同的的值与顺序。 iterable 可以是序列、支持迭代的容器或其它可迭代对象。 如果 iterable 已经是一个列表,将创建并返回其副本,类似于 iterable[:]
。 例如,list('abc')
返回 ['a', 'b', 'c']
而 list( (1, 2, 3) )
返回 [1, 2, 3]
。 如果没有给出参数,构造器将创建一个空列表 []
。
其它许多操作也会产生列表,包括 sorted() 内置函数。
列表实现了所有 一般 和 可变 序列的操作。 列表还额外提供了以下方法:
sort(*, key=None, reverse=False)
此方法会对列表进行原地排序,只使用 <
来进行各项间比较。 异常不会被屏蔽 —— 如果有任何比较操作失败,整个排序操作将失败(而列表可能会处于被部分修改的状态)。
sort() 接受两个仅限以关键字形式传入的参数 (仅限关键字参数):
key 指定带有一个参数的函数,用于从每个列表元素中提取比较键 (例如 key=str.lower
)。 对应于列表中每一项的键会被计算一次,然后在整个排序过程中使用。 默认值 None
表示直接对列表项排序而不计算一个单独的键值。
可以使用 functools.cmp_to_key() 将 2.x 风格的 cmp 函数转换为 key 函数。
reverse 为一个布尔值。 如果设为 True
,则每个列表元素将按反向顺序比较进行排序。
当顺序大尺寸序列时此方法会原地修改该序列以保证空间经济性。 为提醒用户此操作是通过间接影响进行的,它并不会返回排序后的序列(请使用 sorted() 显示地请求一个新的已排序列表实例)。
sort() 方法确保是稳定的。 如果一个排序确保不会改变比较结果相等的元素的相对顺序就称其为稳定的 --- 这有利于进行多重排序(例如先按部门、再接薪级排序)。
有关排序示例和简要排序教程,请参阅 排序指南 。
CPython 实现细节: 在一个列表被排序期间,尝试改变甚至进行检测也会造成未定义的影响。 Python 的 C 实现会在排序期间将列表显示为空,如果发现列表在排序期间被改变将会引发 ValueError。
元组
元组是不可变序列,通常用于储存异构数据的多项集(例如由 enumerate() 内置函数所产生的二元组)。 元组也被用于需要同构数据的不可变序列的情况(例如允许存储到 set 或 dict 的实例)。
class tuple([iterable])
可以用多种方式构建元组:
-
使用一对圆括号来表示空元组:
()
-
使用一个后缀的逗号来表示单元组:
a,
或(a,)
-
使用以逗号分隔的多个项:
a, b, c
or(a, b, c)
-
使用内置的 tuple():
tuple()
或tuple(iterable)
构造器将构造一个元组,其中的项与 iterable 中的项具有相同的值与顺序。 iterable 可以是序列、支持迭代的容器或其他可迭代对象。 如果 iterable 已经是一个元组,会不加改变地将其返回。 例如,tuple('abc')
返回 ('a', 'b', 'c')
而 tuple( [1, 2, 3] )
返回 (1, 2, 3)
。 如果没有给出参数,构造器将创建一个空元组 ()
。
请注意决定生成元组的其实是逗号而不是圆括号。 圆括号只是可选的,生成空元组或需要避免语法歧义的情况除外。 例如,f(a, b, c)
是在调用函数时附带三个参数,而 f((a, b, c))
则是在调用函数时附带一个三元组。
元组实现了所有 一般 序列的操作。
对于通过名称访问相比通过索引访问更清晰的异构数据多项集,collections.namedtuple() 可能是比简单元组对象更为合适的选择。
range 对象
range 类型表示不可变的数字序列,通常用于在 for 循环中循环指定的次数。
class range(stop)
class range(start, stop[, step])
range 构造器的参数必须为整数(可以是内置的 int 或任何实现了 __index__() 特殊方法的对象)。 如果省略 step 参数,则默认为 1
。 如果省略 start 参数,则默认为 0
。 如果 step 为零,则会引发 ValueError。
如果 step 为正值,确定 range r
内容的公式为 r[i] = start + step*i
其中 i >= 0
且 r[i] < stop
。
如果 step 为负值,确定 range 内容的公式仍然为 r[i] = start + step*i
,但限制条件改为 i >= 0
且 r[i] > stop
.
如果 r[0]
不符合值的限制条件,则该 range 对象为空。 range 对象确实支持负索引,但是会将其解读为从正索引所确定的序列的末尾开始索引。
元素绝对值大于 sys.maxsize 的 range 对象是被允许的,但某些特性 (例如 len()) 可能引发 OverflowError。
一些 range 对象的例子:
>>>
>>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> list(range(0, 30, 5)) [0, 5, 10, 15, 20, 25] >>> list(range(0, 10, 3)) [0, 3, 6, 9] >>> list(range(0, -10, -1)) [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] >>> list(range(0)) [] >>> list(range(1, 0)) []
range 对象实现了 一般 序列的所有操作,但拼接和重复除外(这是由于 range 对象只能表示符合严格模式的序列,而重复和拼接通常都会违反这样的模式)。
start
start 形参的值 (如果该形参未提供则为 0
)
stop
stop 形参的值
step
step 形参的值 (如果该形参未提供则为 1
)
range 类型相比常规 list 或 tuple 的优势在于一个 range 对象总是占用固定数量的(较小)内存,不论其所表示的范围有多大(因为它只保存了 start
, stop
和 step
值,并会根据需要计算具体单项或子范围的值)。
range 对象实现了 collections.abc.Sequence ABC,提供如包含检测、元素索引查找、切片等特性,并支持负索引 (参见 序列类型 --- list, tuple, range):
>>>
>>> r = range(0, 20, 2) >>> r range(0, 20, 2) >>> 11 in r False >>> 10 in r True >>> r.index(10) 5 >>> r[5] 10 >>> r[:5] range(0, 10, 2) >>> r[-1] 18
使用 ==
和 !=
检测 range 对象是否相等是将其作为序列来比较。 也就是说,如果两个 range 对象表示相同的值序列就认为它们是相等的。 (请注意比较结果相等的两个 range 对象可能会具有不同的 start, stop 和 step 属性,例如 range(0) == range(2, 1, 3)
而 range(0, 3, 2) == range(0, 4, 2)
。)
在 3.2 版更改: 实现 Sequence ABC。 支持切片和负数索引。 使用 int 对象在固定时间内进行成员检测,而不是逐一迭代所有项。
在 3.3 版更改: 定义 '==' 和 '!=' 以根据 range 对象所定义的值序列来进行比较(而不是根据对象的标识)。
3.3 新版功能: start, stop 和 step 属性。
参见
-
linspace recipe 演示了如何实现一个延迟求值版本的适合浮点数应用的 range 对象。