本章将更详细地描述您已经学到的一些内容,并添加了一些新的内容。
5.1 关于列表的更多内容
列表数据类型有一些更多的方法。 以下是列表对象的所有方法:
list.append(x)
将项目添加到列表的末尾;等价于a[ len(a) : ] = [x]
list.extend(L)
通过追加给定列表的所有项目来扩展列表;等价于a[ len(a) : ] = L
list.insert(i, x)
在给定的位置插入一个项目,第一个参数是插入前元素的索引,因此,a.insert(0, x)在列表的最前端插入元素x,a.insert(len(a), x)等价于a.append(x)
list.remove(x)
从列表中移除值为x的第一个项目,如果没有此项目,将会发生错误。
list.pop([i])
在给定的位置移除列表中的项目并返回这个项目。如果未指定索引。a.pop()移除并返回列表中的最后一个项目,方法签名中的i周围的方括号表示参数是可选的,你不应该在那个位置中键入方括号。你将在Python参考库中频繁地看到这个符号。
list.index(x)
返回列表中值为x第一个项目的索引,如果没有此项目,将会发生错误。
list.count(x)
返回列表中x出现的次数
list.sort(cmp=None, key=None, reverse=False)
对列表中的项目进行排序(这个参数可用于自定义排序,查看sorted()以获取解释)
list.reverse()
反转列表中的元素。
使用大多数列表方法的示例:
>>> a = [66.25, 333, 333, 1, 1234.5] >>> print a.count(333), a.count(66.25), a.count('x') 2 1 0 >>> a.insert(2, -1) >>> a.append(333) >>> a [66.25, 333, -1, 333, 1, 1234.5, 333] >>> a.index(333) 1 >>> a.remove(333) >>> a [66.25, -1, 333, 1, 1234.5, 333] >>> a.reverse() >>> a [333, 1234.5, 1, 333, -1, 66.25] >>> a.sort() >>> a [-1, 1, 66.25, 333, 333, 1234.5] >>> a.pop() 1234.5 >>> a [-1, 1, 66.25, 333, 333]
你可能已经注意到像insert,remove或者sort方法只修改了列表,但是并没有打印返回的值,它们默认返回None。
【1】这是Python中所有可变数据结构的设计原则。
5.1.1 将列表用做堆栈
列表方法使得将列表用作堆栈非常容易,在这里添加的最后一个元素是检索的第一个元素(Last-in,First-out-->后进先出法),要将项目添加到堆栈的顶部,请使用append()方法,要从堆栈顶部检索一个项目,请使用不带显示索引的pop()方法。例如:
>>> stack = [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> stack [3, 4, 5, 6, 7] >>> stack.pop() 7 >>> stack [3, 4, 5, 6] >>> stack.pop() 6 >>> stack.pop() 5 >>> stack [3, 4]
5.1.2 将列表用作队列
使用列表作为队列也是可以的。在这里添加的第一个元素是检索的第一个元素(First-in,First-out-->先进先出法),然而,列表对此目的不是有效的,虽然从列表末尾的追加和弹出是快速的,但是从列表的开始执行插入或弹出是缓慢的(因为所有其他元素必须移动一个)。
要实现队列,请使用collections.queue()方法,它为从两端快速追加和弹出而设计。例如:
>>> from collections import deque >>> queue = deque(["Eric", "John", "Michael"]) >>> queue.append("Terry") # Terry arrives >>> queue.append("Graham") # Graham arrives >>> queue.popleft() # The first to arrive now leaves 'Eric' >>> queue.popleft() # The second to arrive now leaves 'John' >>> queue # Remaining queue in order of arrival deque(['Michael', 'Terry', 'Graham'])
5.1.3 函数式编程工具
当与列表一起使用时,有三个内置函数非常有用:filter()、map()和reduce()函数。
filter(function, sequence)返回由function(item)为真的序列中的那些item组成的序列。如果序列是一个str、unicode或者tuple对象,结果将是相同的类型;否则,它总是一个列表。例如,计算由3或5整除的数字序列:
>>> def f(x): return x % 3 == 0 or x % 5 == 0 ... >>> filter(f, range(2, 25)) [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24]
map(function, sequence)为每个序列项目调用function(item),并返回返回值的列表。例如,计算数据的立方:
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
可以传递多于一个序列;该函数必须具有与序列一样多的参数,并且与来自每个序列的相应项目一起调用(或者如果某个序列比另一个序列短,则为None)。例如:
>>> seq = range(8) >>> def add(x, y): return x+y ... >>> map(add, seq, seq) [0, 2, 4, 6, 8, 10, 12, 14]
reduce(function, sequence)返回单值,它通过在序列的前两个项目上调用二进制函数function,然后对结果和下一个项目进行构建获取等等得到最终结果。例如,计算数字1到10的和:
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55
如果序列中只有一个项目,则返回其值,如果序列为空,则引发异常。
可以传递第三个参数指明起始值,在这种情况下,起始值被返回放置到空序列中,且函数首先应用于起始值和第一个序列项,然后应用于结果和下一个项目,以此类推,例如:
>>> def sum(seq): ... def add(x,y): return x+y ... return reduce(add, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0
不要使用这个例子中定义的sum()函数,因为数字求和是这样一个常见的需求,内置函数sum(sequence)已经提供,并且像这样正常工作。
5.1.4 列表解析
列表解析提供了一种简单的方式来创建列表。常见的应用是创建新列表,在这里,每个元素是应用于另外一个序列或者迭代器的每个成员的一些操作结果,或者是创建那些满足特定条件的元素子序列。
>>> squares = [] >>> for x in range(10): ... squares.append(x**2) ... >>> squares [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我们可以得到相同的结果:
squares = [x**2 for x in range(10)]
这也等价于squares = map(lambda x: x**2,range(10)),但它更加简洁和可读。
列表解析由包含表达式,后跟一个for子句,后面有0至多个for或if子句的方括号组成,结果是一个新列表,由在其后的fo语句和if子句的表达式内容计算得来。例如,如果这两个列表的元素不相等,则listcomp组合这两个列表的元素:
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y] [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
它等价于:
>>> combs = [] >>> for x in [1,2,3]: ... for y in [3,1,4]: ... if x != y: ... combs.append((x, y)) ... >>> combs [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
请注意for和if语句在这两个片丢按中的顺序是否相同。如果表达式是元组(例如,前面示例中的(x,y)),则必须用括号括起来。
>>> vec = [-4, -2, 0, 2, 4] >>> # create a new list with the values doubled >>> [x*2 for x in vec] [-8, -4, 0, 4, 8] >>> # filter the list to exclude negative numbers >>> [x for x in vec if x >= 0] [0, 2, 4] >>> # apply a function to all the elements >>> [abs(x) for x in vec] [4, 2, 0, 2, 4] >>> # call a method on each element >>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] >>> [weapon.strip() for weapon in freshfruit] ['banana', 'loganberry', 'passion fruit'] >>> # create a list of 2-tuples like (number, square) >>> [(x, x**2) for x in range(6)] [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] >>> # the tuple must be parenthesized, otherwise an error is raised >>> [x, x**2 for x in range(6)] File "<stdin>", line 1 [x, x**2 for x in range(6)] ^ SyntaxError: invalid syntax >>> # flatten a list using a listcomp with two 'for' >>> vec = [[1,2,3], [4,5,6], [7,8,9]] >>> [num for elem in vec for num in elem] [1, 2, 3, 4, 5, 6, 7, 8, 9]
列表解析可以包含复杂的表达式和嵌套函数:
>>> from math import pi >>> [str(round(pi, i)) for i in range(1, 6)] ['3.1', '3.14', '3.142', '3.1416', '3.14159']
5.1.4.1 嵌套列表解析
列表解析中的初始表达式可以是任意表达式,包括另一个列表解析。
考虑下面的3x4矩阵的示例,其实现长度为4的3个列表的列表:
>>> matrix = [ ... [1, 2, 3, 4], ... [5, 6, 7, 8], ... [9, 10, 11, 12], ... ]
以下列表解析将转置行和列:
>>> [[row[i] for row in matrix] for i in range(4)] [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
正如我们在上一节中看到的,嵌套的listcomp是在它后面的for语句的内容计算得到的,所以这个例子等价于:
>>> transposed = [] >>> for i in range(4): ... transposed.append([row[i] for row in matrix]) ... >>> transposed [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
反过来,这是相同的:
>>> transposed = [] >>> for i in range(4): ... # the following 3 lines implement the nested listcomp ... transposed_row = [] ... for row in matrix: ... transposed_row.append(row[i]) ... transposed.append(transposed_row) ... >>> transposed [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
在现实世界中,你应该更喜欢内置函数处理复杂的流语句,zip()函数将为这个案例做一个伟大的工作:
>>> zip(*matrix)
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
查看Unpacking Argument Lists获取本行*的详情。
5.2 del语句
有一种方法可以从给定索引的列表中删除一个项目,而不是它的值:del语句。 这与返回值的pop()方法不同。 del语句还可以用于从列表中删除切片或清除整个列表(我们之前通过为切片分配空列表来完成)。例如:
>>> a = [-1, 1, 66.25, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.25, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.25, 1234.5] >>> del a[:] >>> a []
del语句也可以用于删除整个变量
>>> del a
以下引用名称a将引发错误(至少直到为其分配了另外一个值),我们会在以后找到其他用途。
5.3 元组和序列
>>> t = 12345, 54321, 'hello!' >>> t[0] 12345 >>> t (12345, 54321, 'hello!') >>> # Tuples may be nested: ... u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) >>> # Tuples are immutable: ... t[0] = 88888 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> # but they can contain mutable objects: ... v = ([1, 2, 3], [3, 2, 1]) >>> v ([1, 2, 3], [3, 2, 1])
>>> empty = () >>> singleton = 'hello', # <-- note trailing comma >>> len(empty) 0 >>> len(singleton) 1 >>> singleton ('hello',)
>>> x, y, z = t
5.4 集合
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> fruit = set(basket) # create a set without duplicates >>> fruit set(['orange', 'pear', 'apple', 'banana']) >>> 'orange' in fruit # fast membership testing True >>> 'crabgrass' in fruit False >>> # Demonstrate set operations on unique letters from two words ... >>> a = set('abracadabra') >>> b = set('alacazam') >>> a # unique letters in a set(['a', 'r', 'b', 'c', 'd']) >>> a - b # letters in a but not in b set(['r', 'd', 'b']) >>> a | b # letters in either a or b set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l']) >>> a & b # letters in both a and b set(['a', 'c']) >>> a ^ b # letters in a or b but not both set(['r', 'd', 'b', 'm', 'z', 'l'])
>>> a = {x for x in 'abracadabra' if x not in 'abc'} >>> a set(['r', 'd'])
5.5 字典
>>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel {'sape': 4139, 'guido': 4127, 'jack': 4098} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel {'guido': 4127, 'irv': 4127, 'jack': 4098} >>> tel.keys() ['guido', 'irv', 'jack'] >>> 'guido' in tel True
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> {x: x**2 for x in (2, 4, 6)} {2: 4, 4: 16, 6: 36}
>>> dict(sape=4139, guido=4127, jack=4098) {'sape': 4139, 'jack': 4098, 'guido': 4127}
5.6 循环技术
>>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe
>>> questions = ['name', 'quest', 'favorite color'] >>> answers = ['lancelot', 'the holy grail', 'blue'] >>> for q, a in zip(questions, answers): ... print 'What is your {0}? It is {1}.'.format(q, a) ... What is your name? It is lancelot. What is your quest? It is the holy grail. What is your favorite color? It is blue.
>>> for i in reversed(xrange(1,10,2)): ... print i ... 9 7 5 3 1
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> for f in sorted(set(basket)): ... print f ... apple banana orange pear
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.iteritems(): ... print k, v ... gallahad the pure robin the brave
>>> import math >>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8] >>> filtered_data = [] >>> for value in raw_data: ... if not math.isnan(value): ... filtered_data.append(value) ... >>> filtered_data [56.2, 51.7, 55.3, 52.5, 47.8]
5.7 更多条件
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim'
5.8 比较序列和其他类型
(1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)