4.6. Sequence Types — list
, tuple
, range
python拥有三种基本的序列类型:lists
, tuples
和range
。其他的序列类型包括二进制类型(binary data
)和字符串类型(text strings
)将会在其他章节内进行描述.
4.6.1. Common Sequence Operations
下面的操作支持大部分的序列类型,包括可变类型和不可变类型。python里提供的collections.abc.Sequence ABC
是为了更容易在自定义序列类型上正确实现这些操作。
这个表格列举的操作是根据优先级排序的。在列表里,s
和t
是相同的序列类型。n
,i
,j
是整数,x
是满足任何类型限制的任意对象。
in
和not in
操作有相同的优先级.
+
和*
操作与相应的数字操作具有相同的优先级。[3]
。
Operation | Result | Notes |
---|---|---|
x in s |
True if an item of s is equal to x, else False
|
(1) |
x not in s |
False if an item of s is equal to x, else True
|
(1) |
s + t |
the concatenation of s and t | (6)(7) |
s * n or n * s
|
equivalent to adding s to itself n times | (2)(7) |
s[i] |
ith item of s, origin 0 | (3) |
s[i:j] |
slice of s from i to j | (3)(4) |
s[i:j:k] |
slice of s from i to j with step k | (3)(5) |
len(s) |
length of s | |
min(s) |
smallest item of s | |
max(s) |
largest item of s | |
s.index(x[, i[, j]]) |
index of the first occurrence of x in s (at or after index i and before index j) | (8) |
s.count(x) |
total number of occurrences of x in s |
相同的序列类型还支持比较。具体地说,tuple
和list
通过字典顺序来比较对应的元素。这表示如果两个序列相等,则必须每个对应的元素都要相同,而且两个序列的类型和长度必须相同。(想参阅对应的详细信息,可以参考Comparisons )
标记:
1.x not in s
--> in
和not in
不止用于一般的的包容测试,一些特殊的序列类型(比如str
,bytes
和bytearray
)也可以使用它们进行包容测试:
>>> "gg" in "eggs"
True
2.s * n or n * s
--> n
小于0
时被视为0
(产生跟s
类型相同的空类型)。请注意,序列s
里面的item并没有被copy,他们被重复引用多次(n
次). 这个问题常常困扰新的python程序员。
考虑以下情况:
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
为什么会发生这种情况呢,因为[[]]
是一个包含一个[]元素的数组,因此[[]] * 3
都是对这个空数组的相同引用,修改任意一个元素都会修改这个单独的列表。
用指针的说法表示就是:创建了一个包含三个指针的数组,这三个指针都指向同一个地址。你可以通过另一种方式创建空数组:
>>>lists = [[] for i in range(3)]
>>> lists[0].append(3)
>>> lists[1].append(5)
>>> lists[2].append(7)
>>> lists
[[3], [5], [7]]
FAQ条目中提供了进一步的说明如何创建多维列表?.
3.s[i]
,s[i:j]
,s[i:j:k]
--> 如果i 和j是负数,i和j就会使用:len(s) + i
或者 len(s) + j
代替,但是-0
还是0
if i < 0:
i = len(s) + i
if j < 0:
j = len(s) + j
s[i:j]
--> 从i
到j
的对s
的切片被定义为具有索引k
的序列,使得i <= k < j
。如果i
或者j
比len(s)
的长度大,使用len(s)
代替。如果i
被省略或者i
是None
,使用0
。如果j
被省略或者j
是None
,使用len(s)
代替。如果i
大于等于j
,则切片为空。s[i:j:k]
-->s
的从i
到j
,具有索引为x = i + n * k
的切片,其中n: 0 <= n < (j - i) / k
.换句话说,指数为:i, i + k, i + 2 * k, i + 3 * k ......
, 当x
达到j
时停止检索,但是x
不包括j
。
当k
是正数时,如果i
或j
比len(s)
大,他们将变为(减少到)len(s)
。
当k
是负数时,如果i
或j
比len(s)
大,他们将变为(减少到)len(s)-1
。
如果i
或者j
被省略或者为None
,他们将会变成结束值,结束值的数值取决于k
的符号。如下所示:
# k不能等于0
# 如果k=None,k = 1
if k == None:
k = 1
if k < 0:
i = len(s) - 1
j = 0
if j > 0:
i = 0
j = len(s) - 1
6.s + t
--> 拼接不可变序列总是产生一个新序列。这意味着通过重复连接建立一个序列将在总序列长度中具有二次运行成本。要获得线性运行时成本,您必须切换到以下其中一个选项:
* 如果拼接的是str类型,你可以生成一个序列,并且可以在末尾使用str.join()或写入一个io.StringIO实例,并在完成时检索其值
*如果拼接的是bytes类型,你可以相似的使用bytes.join()或者io.BytesIO,或者你可以使用bytearray代替,bytearray是可变的并且具有有效的分配机制
*如果拼接的是tuple类型,使用list代替
*如果拼接的是其他类型,请查看相关的类文档
7.s + t
--> 某些序列类型(如range
)仅支持遵循特定模式的项目序列,因此不支持序列拼接或重复。
-
s.index(x[, i[, j]])
--> 当在s
中没有找到x
时index
raisesValueError
。不是所有的类型都支持传递附加的参数i
和j
。这两个参数允许有效的搜索序列的子部分。传递额外的参数大致相当于使用s [i:j] .index(x)
,只是不复制任何数据,并且返回的索引是相对于序列的开始而不是切片的开始。
4.6.2. 不可变序列(Immutable Sequence Types)
唯一不可变的序列类型通常实现的操作不是通过可变序列类型实现的,这是对内置的hash()
的支持。
这种支持允许将不可变序列(如tuple
实例)用作dict
的key
,并存储在set
和frozenset
实例中。
尝试hash包含不可hash的不可变序列将导致TypeError。
4.6.3. 可变序列(Mutable Sequence Types)
下表中的操作是在可变序列类型上定义的。python里提供的collections.abc.MutableSequence ABC
是为了更容易在自定义序列类型上正确实现这些操作。
在表中s
是一个可变序列类型的实例,t
是任何可迭代的对象,x
是一个任意的对象,满足s
施加的任何类型和数值限制(例如bytearray
只接受满足值限制'0 <= x <= 255'的整数)。
Operation | Result | Notes |
---|---|---|
s[i] = x |
item i of s is replaced by x | |
s[i:j] = t |
slice of s from i to j is replaced by the contents of the iterable t | |
del s[i:j] |
same as s[i:j] = []
|
|
s[i:j:k] = t |
the elements of s[i:j:k] are replaced by those of t
|
(1) |
del s[i:j:k] |
removes the elements of s[i:j:k] from the list |
|
s.append(x) |
appends x to the end of the sequence (same ass[len(s):len(s)] = [x] ) |
|
s.clear() |
removes all items from s (same as del s[:] ) |
(5) |
s.copy() |
creates a shallow copy of s (same as s[:] ) |
(5) |
s.extend(t) or s += t
|
extends s with the contents of t (for the most part the same as s[len(s):len(s)] = t ) |
|
s *= n |
updates s with its contents repeated n times | (6) |
s.insert(i, x) |
inserts x into s at the index given by i (same as s[i:i]= [x] ) |
|
s.pop([i]) |
retrieves the item at i and also removes it from s | (2) |
s.remove(x) |
remove the first item from s where s[i] == x
|
(3) |
s.reverse() |
reverses the items of s in place | (4) |
标记:
- 序列
t
的长度必须和切片的长度一样. - 参数
i
默认是-1
, 所以默认返回并删除最后一个元素。 - 当
s
中没有发现x
时,remove
raisesValueError
. -
reverse()
方法在倒置大序列时可以节省空间。为了提醒用户它是以副作用的方式运行的,它不会返回相反的顺序。 - 为了与不支持切片操作的可变容器的接口(如
dict
和set)保持一致,使用了clear()
和copy()
New in version 3.3:clear()
andcopy()
methods. - 值n是一个整数,或者一个实现了
__index__()
的对象。n为零和负值时表示清除序列。序列中的item不是被复制;它们被多次引用,如Common Sequence Operations下的s * n
所述。
4.6.4. Lists
数组是可变序列,经常用于存储同类项目的集合(精确的相似度因应用程序而异)。
class list([iterable])
Lists may be constructed in several ways:
列表可以以几种方式构建:
- 用一对方括号表示一个空数组:
[]
- 使用方括号,用逗号分隔item:
[a]
,[a, b, c]
- for循环一个list(Using a list comprehension):
[x for x in iterable]
- 使用类型构造函数:
list()
orlist(iterable)
构造函数list(iterable)
构建一个列表,其items和iterable的item相同,并且item的顺序也相同。iterable可能是一个序列,支持迭代的容器,也可以是迭代器对象。如果iterable也是一个list,将会copy一个新的list并且返回,相当于iterable[:]。如果没有参数传入,创建一个空序列。举个例子:
>>>list("abc")
['a', 'b', 'c']
>>>list((1, 2, 3))
[1, 2, 3]
>>>list()
[]
许多其他操作也可以创建lists,包括内建函数sorted()
.
list支持所有通用common方法和可变mutable方法(即以上两个表格里的所有方法)。并且还支持以下的方法:
sort(*, key=None, reverse=False)
这个方法对列表进行排序,通过<
(大小)比较对list里的item
进行比较。异常不会被抑制 - 如果任何比较操作失败,整个排序操作将失败(并且列表可能会保留在部分修改状态)。
>>>l1 = [3, 2, 6, 3, 'xl', 9, 0] # 注意当前l1的排列顺序
>>>l1.sort() # 对l1进行排序sort,报错
Traceback (most recent call last):
File "xx.py", line 91, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
>>>l1 # 重新查看l1的数据,发现数据的排列顺序已经改变
[2, 3, 3, 6, 'xl', 9, 0]
sort()
accepts two arguments that can only be passed by keyword (keyword-only arguments):
sort()
接受两个只能通过关键字传递的参数key
,reverse
key
指定一个用于从每个列表元素提取比较键的参数的函数(例如key = str.lower
)。对应于列表中每个项目的键被计算一次,然后用于整个排序过程。 “None”的默认值意味着列表项直接排序而不需要计算单独的键值。
>>>l2 = ['5', '9', 9, 8, 7, '3', 1]
>>>l2.sort() # 类型不同,无法比较,报错
Traceback (most recent call last):
File "xx.py", line 91, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
>>>l2.sort(key=int) #使用int()作用于每一个元素,然后进行比较
>>>l2
[1, '3', '5', 7, 8, '9', 9]
functools.cmp_to_key()
可用于将2.x风格的cmp
方法转化为key
方法
reverse
是一个布尔值。如果设置为True
,则列表元素按照相反的顺序进行排序(逆序)。
这种方法在排序大序列时可以有效节省内存空间。为了提醒用户,它运行的副作用,此方法不返回排好序的序列(使用[sorted()
)
sort()
方法保证稳定。如果确保不会更改比较相等的元素的相对顺序,则排序是稳定的 - 这对于多次排序很有帮助。
CPython实现细节:在列表正在排序时,试图进行变异甚至检查列表的效果时,列表是undefined
。CPython实现使得列表在持续时间内显示为空,并且如果列表在排序过程中发生了变化,它可以检测到ValueError
。
4.6.5. Tuples
元组是不可变的序列,通常用于存储异构数据的集合(例如enumerate()
生成的2元组)。 元组也用于需要存储不变序列的同类数据的情况(例如允许存储在set
或dict
实例中)。
class tuple([*iterable*])
元组可以通过以下方式创建:
- 使用一对小括号来创建一个空tuple:
()
- 使用一个逗号结尾的单个tuple:
a,
or(a,)
- 用逗号分隔项目:
a, b, c
or(a, b, c)
- 使用内置函数
tuple()
:tuple()
ortuple(iterable)
构造函数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))
是一个以3-tuple作为唯一参数的函数调用。
tuple支持所有的通用序列操作
对于数据的异质集合,其中通过名称访问比由索引访问更清晰,collections.namedtuple()
可能是一个比简单的元组对象更合适的选择。
4.6.6. Ranges
range
类型表示numbers的不可变序列,并通常用于for
循环中。
class range(stop)
class range(start, stop[, step])
range
构造函数的参数必须是整数(内置[int
]或任何实现__index__
特殊方法的对象)。
如果省略step
参数,则默认为1
。
如果省略start
参数,则默认为0
。
如果step
为零,则引发'ValueError`
对于step > 0
,range
的实例对象r
的内容由以下公式确定:r[i] = start + step * i where (i >= 0 and r[i] < stop)
.请注意,这里r[i] < stop
.
对于step < 0
,range
的实例对象r
的内容由以下公式确定:r[i] = start + step * i where (i >= 0 and r[i] > stop)
.请注意,这里r[i] > stop
.
# 伪代码
if step > 0:
int i = 0
while r[i] < stop:
r[i] = start + step * i
i += 1
if step < 0:
int i = 0
while r[i] > stop:
r[i] = start + step * i
i += 1
如果r [0]
不符合值约束,range
对象将为空。range
确实支持负指数,但这些被解释为从正指数确定的序列末尾开始的索引。(可以参考切片的理解)
range
的元素中包含有大于sys.maxsize
的元素是被允许的,但是一些方法可能会引发OverflowError
,比如说len()
Range examples:
>>>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))
[]
范围实现所有通用序列操作,除了连接和重复(由于范围对象只能表示序列遵循严格的模式,重复和连接通常会违反该模式)。
start
start参数的值(如果参数未提供,则为0
)
stop
stop参数的值
step
step参数的值(如果参数未提供,则为1
)
range
类型比list
或tuple
好的一个地方是:一个range
对象将总是采取相同(小)的内存量,无论它代表的范围的大小(因为它只存储“start”,“stop”和“step”的值,在使用时再根据需要计算单个项目和子范围)。
Range对象支持collections.abc.Sequence ABC
方法,提供诸如包含测试,元素索引查找,切片和负指数支持等功能:
>>>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
序列对象表示的值相同,则它们被认为是相等的。 (请注意,比较相等的两个范围对象可能会有不同的start
,stop
和step
.例如range(0)== range(2,1,3)
或range(0,3,2)== range(0,4) ,2)
。
>>>range(0)
range(0, 0)
>>>range(2, 1, 3)
range(2, 1, 3)
>>>list(range(0))
[]
>>>list(range(2, 1, 3))
[]
在版本3.2中更改:实现序列ABC。支持切片和负指数。在恒定时间测试[int
]成员的对象,而不是迭代所有项目。
在版本3.3中更改:定义'=='和'!='以根据它们定义的值序列比较范围对象(而不是根据对象标识进行比较)。
3.3版新增功能:start
,stop
和step
属性。
也可以看看
- linspace recipe显示如何实现适合浮点应用程序的惰性版本的范围
通用序列(common)操作表格摘抄
x in s | True if an item of s is equal to x, else False | (1) |
x not in s | False if an item of s is equal to x, else True | (1) |
s + t | the concatenation of s and t | (6)(7) |
s * n or n * s | equivalent to adding s to itself n times | (2)(7) |
s[i] | ith item of s, origin 0 | (3) |
s[i:j] | slice of s from i to j | (3)(4) |
s[i:j:k] | slice of s from i to j with step k | (3)(5) |
len(s) | length of s | |
min(s) | smallest item of s | |
max(s) | largest item of s | |
s.index(x[, i[, j]]) | index of the first occurrence of x in s (at or after index i and before index j) | (8) |
s.count(x) | total number of occurrences of x in s |
可变序列(mutable)操作表格摘抄
s[i] = x | item i of s is replaced by x | |
s[i:j] = t | slice of s from i to j is replaced by the contents of the iterable t | |
del s[i:j] | same as s[i:j] = [] | |
s[i:j:k] = t | the elements of s[i:j:k] are replaced by those of t | (1) |
del s[i:j:k] | removes the elements of s[i:j:k] from the list | |
s.append(x) | appends x to the end of the sequence (same as s[len(s):len(s)] = [x]) | |
s.clear() | removes all items from s (same as del s[:]) | (5) |
s.copy() | creates a shallow copy of s (same as s[:]) | (5) |
s.extend(t) | or s += t extends s with the contents of t (for the most part the same as s[len(s):len(s)] = t) | |
s *= n | updates s with its contents repeated n times | (6) |
s.insert(i, x) | inserts x into s at the index given by i (same as s[i:i] = [x]) | |
s.pop([i]) | retrieves the item at i and also removes it from s | (2) |
s.remove(x) | remove the first item from s where s[i] == x | (3) |
s.reverse() | reverses the items of s in place | (4) |