Python Chapter 2 列表和元组

序列概览

Python包含6种内建的序列,列表元组,字符串,Unicode字符串,buffer对象,xrange对象.

列表可以修改,元组不可以修改.在几乎所有的情况下列表都可以替代元组,但是也有例外,比如:使用元组作为字典的键.因为键不可修改,所以就不能使用列表.

在需要操作一组数值的时候,序列很好用.同时,序列也可以包含其他的序列.

>>> edward = ['Edward Gumby', 42]
>>> john = ['John Smith', 50]
>>> database = [edward, john]
>>> database
[['Edward Gumby', 42], ['John Smith', 50]]
>>> database[0][0]
'Edward Gumby'

注意:Python中还有一种名为容器的数据结构.容器基本上是包含其他对象的任意对象.序列(例如列表和元组)和映射(例如字典)是两类主要的容器.序列中的每个元素都有自己的编号,而映射中的每个元素则有一个名字(也称为键).至于既不是序列也不是映射的容器类型,集合(set)就是一个例子.

通用序列操作

所有序列类型都可以进行的操作:索引,分片,加,乘,以及检查某个元素是否属于序列的成员(成员资格).除此外,Python还有:计算序列长度.找出最大元素和最小元素的内建函数.

注意:迭代.依次对序列中的每个元素重复执行某些操作.

索引

索引编号从0开始递增(0,1,2,3,…).如果使用负数索引时,从右边开始,也就是最后一个元素的索引为-1,从右向左依次递减(…-3,-2,-1).

>>> str = 'hello'
>>> str[0]
'h'
>>> str[-5]
'h'

字符串的字面值(就此而言,其他序列字面量亦可)能够直接使用索引,而不需要一个变量引用它们.两种做法的效果是一样的:

>>> 'hello'[0]
'h'
>>> 'hello'[-5]
'h'

如果一个函数调用返回一个序列,那么可以直接对返回结果进行索引操作.例如:

>>> f = raw_input('Year: ')
Year: 1234
>>> f = raw_input('Year: ')[3]
Year: 1234
>>> f
'4'

分片

分片的原则是"前闭后开

>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[3:6]
[4, 5, 6]
>>> numbers[0:1]
[1]
>>> numbers[-3:-1]
[8, 9]
>>> numbers[-3:0]
[]
>>> numbers[-3:]
[8, 9, 10]
>>> numbers[:3]
[1, 2, 3]
>>> numbers[:]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

也可以在分片中加入步长

>>> numbers[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> numbers[0:10:2]
[1, 3, 5, 7, 9]
>>> numbers[3:6:3]
[4]
>>> numbers[8:3:-1]
[9, 8, 7, 6, 5]
>>> numbers[10:0:-2]
[10, 8, 6, 4, 2]
>>> numbers[0:10:-2]
[]
>>> numbers[::-2]
[10, 8, 6, 4, 2]
>>> numbers[5::-2]
[6, 4, 2]
>>> numbers[:5:-2]
[10, 8]

步长不能为0,但可以是负数,即从右到左提取元素.

对于一个正数步长,Python会从序列的头部开始向右提取元素,直到最后一个元素;而对于负数步长,则是从序列的尾部开始向左提取元素,直到第一个元素.

序列相加

通过使用'+'可以进行序列的连接操作:

>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> 'hello ' + 'world'
'hello world'
>>> [1, 2, 3] + 'hello'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list

注意:两种相同类型的序列才可以进行连接操作

乘法

用数字t乘以一个序列会生成新的序列,在新的序列中,原来的序列将被重复t次.

>>> 'python' * 5
'pythonpythonpythonpythonpython'
>>> [1, 2, 3] * 4
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

None是Python的一个内建值,表示"这里什么也没有".

初始化一个列表:

>>> s = [None] * 10
>>> s
[None, None, None, None, None, None, None, None, None, None]

成员资格

可以使用'in'运算符检查一个值是否在序列中,返回True or False.

>>> str = 'rw'
>>> 'w' in str
True
>>> 's' in str
False
>>> str in str
True
>>> 'wr' in str
False
>>> 'rw' in str
True
>>> user = ['mm', 'gg']
>>> raw_input('Enter your name: ') in user
Enter your name: mm
True
>>> str = 'ddd get some money'
>>> 'ddd' in str
True
>>> database = [ ['albert', 1], ['wang', 2] ]
>>> ['albert', 1] in database
True

长度,最小值和最大值

len, min, max 可以返回序列元素的个数,最小和最大元素.

>>> num = [100, 23, 342]
>>> len(num)
    3
    >>> max(num)
    342
    >>> min(num)
    23
    >>> str = ['wang', 'yan', 'ttt']
    >>> max(str)
    'yan'
    >>> min(str)
    'ttt'
    >>> max(1, 2, 3, 4)
    4
    >>> min(1, 2, 3, 4)
    1

列表:Python 的"苦力"

列表不同于字符串和元组的地方是:列表是可变的

list 函数

可以使用 list 函数创建列表.list 函数适用于所有类型的序列.

>>> list('wang')
['w', 'a', 'n', 'g']
>>> ''.join(['w','y'])
'wy'

使用 join 可以将字符组成的列表转换成字符串.

基本的列表操作

改变列表的方法:元素赋值,元素删除,分片赋值以及列表方法(并不是所有的列表方法都真正地改变列表).

元素赋值

>>> x = [1, 2, 3]
>>> x
[1, 2, 3]
>>> x[0] = 10
>>> x
[10, 2, 3]
>>> x[4] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

不能为一个元素不存在的位置赋值.

删除元素,使用 del 语句来实现:

>>> x = [1, 2, 3]
>>> x
[1, 2, 3]
>>> del x[0]
>>> x
[2, 3]
>>> del x[10]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

分片赋值

>>> names = list('perl')
>>> names
['p', 'e', 'r', 'l']
>>> names[2:] = list('ar')
>>> names
['p', 'e', 'a', 'r']
>>> 
>>> names = list('perl')
>>> names
['p', 'e', 'r', 'l']
>>> names[1:] = list('ython i love you')
>>> names
['p', 'y', 't', 'h', 'o', 'n', ' ', 'i', ' ', 'l', 'o', 'v', 'e', ' ', 'y', 'o', 'u']

分片赋值语句可以在不需要替换任何原有元素的情况下插入新的元素.也可以通过分片赋值来删除元素.

>>> nums = [1, 5]
>>> nums[1:1] = [2, 3, 4]
>>> nums
[1, 2, 3, 4, 5]
>>> 
>>> nums[1:4] = []
>>> nums
[1, 5]

上面例子的结果和 del nums[1:4] 的一样.也可以使用1以外的步长,甚至是负数进行分片.

列表方法

append 方法用于在列表的末尾追加新的对象:

>>> lst = [1, 2, 3]
>>> lst
[1, 2, 3]
>>> lst.append(2)
>>> lst
[1, 2, 3, 2]

count 方法统计某个元素在列表中出现的次数:

>>> ['to', 'be', 'or', 'not', 'to', 'be'].count('to')
2
>>> x = [ [1, 2], 1, 1, [2, 1, [1, 2]] ]
>>> x.count(1)
2
>>> x.count([1, 2])
1

extend 方法可以在列表的末尾一次性追加另一个序列中的多个值.换句话说,就是可以用新的序列扩展原有的列表:

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]

如果使用 a = a + b 的话,会降低效率,并且也不是一个原位置操作.

我们也可以使用分片来实现相同的效果:

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a[len(a):] = b
>>> a
[1, 2, 3, 4, 5, 6]

index 方法用于从列表中找出某个值第一个匹配项的索引位置:

>>> knights = ['we', 'are', 'the', 'knights', 'who', 'say', 'ni']
>>> knights.index('the')
2
>>> knights.index('nonoo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'nonoo' is not in list

当搜索单词'nonoo'时,会引发一个异常,因为这个单词没有被找到.

insert 方法用于将对象插入到列表中:

>>> nums = [1, 2, 3, 4, 5]
>>> nums.insert(3, 'four')
>>> nums
[1, 2, 3, 'four', 4, 5]

与extend方法一样,insert 方法的操作也可以用分片赋值来实现.

>>> nums = [1, 2, 3, 4, 5]
>>> nums[3:3] = ['four']
>>> nums
[1, 2, 3, 'four', 4, 5]

pop 方法会移除列表中的一个元素(默认是最后一个),并且返回该元素的值:

>>> x = [1, 2, 3]
>>> x.pop()
3
>>> x
[1, 2]
>>> x.pop(0)
1
>>> x
[2]
>>> x.pop()
2
>>> x
[]
>>> x.pop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: pop from empty list

注意:pop 方法是唯一一个既能修改列表又返回元素值(除了 None )的方法.

使用 pop 和 append 方法可以模拟栈的操作.

remove 方法用于移除列表中某个值的第一个匹配项:

>>> x = ['to', 'be', 'or', 'not', 'to', 'be']
>>> x.remove('to')
>>> x
['be', 'or', 'not', 'to', 'be']
>>> x.remove('bee')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

remove 是一个没有返回值的原位置改变方法.它修改了列表却没有返回值,这与 pop 方法相反.

reverse 方法将列表中的元素反向存放:

>>> x = [1, 2, 3]
>>> x
[1, 2, 3]
>>> x.reverse()
>>> x
[3, 2, 1]



提示:如果需要对一个序列进行反向迭代,那么可以使用 reversed 函数.这个函数并不返回一个列表,而是返回一个迭代器(iterator)对象.尽管如此,使用 list 函数把返回的对象转换成列表也是可行的:

>>> x = [1, 2, 3]
>>> list(reversed(x))
[3, 2, 1]

sort 方法在原位置(改变原来的列表)对列表进行排序.

>>> x = [2, 3, 1, 9, 5]
>>> x.sort()
>>> x
[1, 2, 3, 5, 9]
>>> print x.sort()
None

>>> x = [4, 6, 2, 1, 7, 9]
>>> y = x[:]
>>> y
[4, 6, 2, 1, 7, 9]
>>> y.sort()
>>> y
[1, 2, 4, 6, 7, 9]
>>> x
[4, 6, 2, 1, 7, 9]

再次调用 x[:] 得到的是包含了 x 所有元素的分片,这是一种很有效率的复制整个列表的方法.只是简单地把 x 赋值 y 是没用的,因为这样就让 x 和 y 都指向同一个列表了.

>>> x = [2, 1, 5, 3, 7]
>>> y = x
>>> y.sort()
>>> y
[1, 2, 3, 5, 7]
>>> x
[1, 2, 3, 5, 7]

另一种获取已排序的列表副本的方法是,使用 sorted 函数:

>>> x = [4, 6, 2, 1, 7, 9]
>>> y = sorted(x)
>>> x
[4, 6, 2, 1, 7, 9]
>>> y
[1, 2, 4, 6, 7, 9]

这个函数实际上可以用于任何一个序列,却总是返回一个列表:

>>> sorted('python')
['h', 'n', 'o', 'p', 't', 'y']

高级排序 如果希望元素能按照特定的方式进行排序,可以通过使用 compare(x, y) 的形式自定义比较函数.compare(x,y) 函数会在 xy 时返回正数,如果 x=y 则返回0(根据你的定义).定义好该函数之后,就可以提供给 sort 方法作为参数了.内建函数 cmp 提供了比较函数的默认实现方式:

>>> def cmpare(x, y):
...     if x > y:
...             return -1
...     elif x < y:
...             return 1
...     else:
...             return 0
... 
>>> numbers = [5, 2, 9, 7]
>>> numbers.sort(cmpare)
>>> numbers
[9, 7, 5, 2]
>>> numbers.sort(cmp)
>>> numbers
[2, 5, 7, 9]

sort 方法有另外两个可选的参数:key 和 reverse.参数 key 与参数 cmp 类似,必提供一个在排序过程中使用的函数.然而,该函数并不是直接用来确定对象的大小,而是为每个元素创建一个,然后所有元素根据键来排序.因此,如果要跟就元素的长度进行排序,那么可以使用 len 作为键函数:

>>> x = ['aardvark', 'abalone', 'acme', 'add', 'aerate']
>>> x.sort(key=len)
>>> x
['add', 'acme', 'aerate', 'abalone', 'aardvark']

另一个关键字 reverse 是简单的布尔值(True或者是False),用来指明列表是否要进行反向排序.

>>> x = [4, 5, 2, 1, 7, 9]
>>> x.sort(reverse=True)
>>> x
[9, 7, 5, 4, 2, 1]

cmp, key, reverse 参数都可以用于 sorted 函数.在多数情况下,为 cmp 或 key 提供自定义函数是非常有用的.



提示:如果想了解更多有关排序的内容,可以查看 Andrew Dalke 的"Sortint Mini-HOWTO",链接是:https://wiki.python.org/moin/HowTo/Sorting.


元组:不可变序列

元组和列表一样,也是一种序列.唯一的不同是,元组不能修改(并且没有像列表一样的方法).创建元组的方法很简单:如果你用逗号分隔了一些值,那么你就自动创建了元组.

>>> 1, 2, 3
(1, 2, 3)
>>> 'q', 'w', 'e'
('q', 'w', 'e')
>>> (1, 2, 3)
(1, 2, 3)
>>> ()
()

空元组可以用没有包含内容的两个圆括号来表示.只包含一个值的元组需要加逗号:

>>> 42
42
>>> 42.
42.0
>>> 42,
(42,)
>>> (42,)
(42,)
>>> (42)
42

>>> 3 * (40 + 2)
126
>>> 3 * (40 + 2 ,)
(42, 42, 42)

tuple 函数

tuple 函数的功能与 list 函数基本上是一样的:以一个序列作为参数并把它转换为元组.如果参数就是元组,那么该参数就会被原样返回:

>>> tuple([1, 2, 3])
(1, 2, 3)
>>> tuple('abc')
('a', 'b', 'c')
>>> tuple((1, 2, 3))
(1, 2, 3)

基本元组操作

元组其实并不复杂——除了创建和访问元组元素之外,也没有太多其他操作,可以参考其他类型的序列来实现:

>>> x = 1, 2, 3
>>> x[1]
2
>>> x[0:2]
(1, 2)

元组的分片还是元组.

元组存在的意义


  • 元组可以在映射(和集合的成员)中当作键使用——而列表则不行.
  • 元组作为很多内建函数和方法的返回值存在,也就是说你必须对元组进行处理.只要不尝试修改元组,那么,"处理"元组在绝大多数情况下就是把它们当作列表来进行操作(除非需要使用一些元组没有的方法,例如 index 和 count).