又有很长的时间过去了,继续推荐Python Tutorial的进程。
本文主要针对官方Python Tutorial中第5小节的内容进行有选择性的分析,还是遵循本系列文档的风格,所讨论的内容都是给我留下一些印象的,或者是一般不太注意的。若有错误,欢迎大家批评指正。
应该说如果前4小节的内容您都理解透彻了,那么用Python来写一些基本的程序应该没什么太大问题。从本小节开始,Tutorial中的内容都是更详细的讨论Python的某些特点。本节的一开始对List类型进行了更详细的讨论。List类型主要有以下常见的方法:
list.append(x) #在列表末尾添加元素x list.extend(L) #将列表L追加在当前列表后,以扩展列表 list.insert(i, x) list.remove(x) list.pop([i]) list.index(x) list.count(x) list.sort() list.reverse()
其中的[i]表示该参数是可选的,相信通过这些方法的名字你就可以很好的明白其作用。这里罗列出来也算是一个基本的回顾。
可以发现,可以通过List的append和pop方法将一个List当作一个栈来用。不仅如此,通过其它库的辅助,List还可以作为队列来使用。
为了使List可以用作队列,我们通过以下示例来说明:
>>> 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'])
可以发现,为了将其用作队列,我们导入deque(双端队列)这个库,这样就可以通过append和popleft实现队列的基本功能。
在Python中有三个非常有用的内建函数可以和List类型一同使用:filer(),map()和reduce()。
filter(function, sequence)返回一个序列,其是有sequence组成的,并且对于sequence里的每一个item,function(item)为true。除非sequence是一个string或tuple,那样的话其返回类型还是string或tuple,否则其返回结果的类型为list。举例如下:
>>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23]
可以看到,f(x)返回的结果为不能被2和3整除的数,filter返回的就是2-25之间不能被2和3整除的数。当然,这里的f可以用lamda表达式来代替,这里不讨论这个问题。
map(function, sequence)也是返回一个序列,基本仿照之前filter函数的意义,其返回对sequence中的item调用function后的结果。通过filter(过滤)和map(映射)的中文含义我们也应该可以理解它们的行为。对map(),举例如下:
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
对于sequence参数,可以不止有一个。当然,此时就要求function函数的参数也是和sequence参数的个数是匹配的:
>>> 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),其通过从调用sequence中的前两个元素开始,之后通过用function以这前两个元素为参数计算后的结果作为一个参数,并与第三个元素一起又作为两个function的参数,以此类推,最终返回一个值。例如计算从1-10的和,可以用如下的方式:
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55
如果sequence中只有一个元素,那么就直接返回那个元素;如果sequence是空的,则会引起一个异常。并且对于reduce函数,其还可以有第三个参数,用来指明开始reduce的起始位置,这里就不举例了。需要说明的是,请不要使用这种reduce的方式来实现sum这个功能,Python中内建的sum(sequence)函数已经提供了这样的功能,这里只是用sum这样的功能来解释reduce的使用。
所谓List解析就是指,在创建List时,我们可以用表达式的方式来描述List的构成。举例如下:
>>>squares = [x**2 for x in range(10)] >>>squares [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [(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)]
可以看到,在[]内我们首先定义了元素的类型,之后是通过for和if语句描述元素产生的规则。对于tuple类型的元素,必须要加上圆括弧。
这里再举一个例子,我们可以通过两个for语句,来解开一个嵌套的List:
>>> 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]
tuple和list有很多相似的地方,但是需要注意的是,tuple的元素是不可变的,而list是可变的。tuple中有两种操作是非常有用的:打包(packing)和解包(unpacking)。举例如下:
>>> t = 12345, 54321, 'hello!' >>> t[0] 12345 >>> t (12345, 54321, 'hello!')
>>> x, y, z = t
前者将不同类型的元素打包成一个元组,而后者将t元组进行解包,将三个元素分别映射到x、y和z。
set表示集合,集合类型中的元素都是无序的,并且set类型中没有重复的元素。下面的代码片段很好地解释了set类型的特点及一些对其的操作:
>>> 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'])
和List一样,Python也可以对set类型进行解析来创建set:
>>> a = {x for x in 'abracadabra' if x not in 'abc'} >>> a set(['r', 'd'])
字典类型和其它语言中可能有的关联数组有关。用一句话来表示字典类型:字典类型就是一个无序的key : value结合,且在一个字典内key是唯一的。字典类型可以用大括号来创建,也可以与集合类型相似,用dict()函数来构造字典类型。举个例子来说明:
>>> 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}
可以看到,key()方法会返回字典中的所有key。并且在用dict()函数创建字典时,key和value的对应既可以用冒号也可以用等号。并且字典类型也同样支持解析。
在遍历一个序列时,如果想同时获取序号和元素值,可以通过使用enumerate()函数:
>>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe
如果想安装字典序来遍历一个序列,可以通过sorted()函数来实现:
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> for f in sorted(set(basket)): ... print f ... apple banana orange pear
遍历字典时,同时获取key和value的方法也非常简单,只需用到iteritems()方法:
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.iteritems(): ... print k, v ... gallahad the pure robin the brave
在if或while语句中,我们都会添加很多条件来表明某个语句块的执行与否。这里提一些关于比较条件的说明。
对于条件a < b == c,其表示的是判断a是否小于b,并且b是否等于c。并不是说用a < b的比较运算结果再和c进行比较。
请看下面这个例子:
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim'
或许有的人看的这个代码,会认为non_null是不是应该被赋值成True了?不过,可以看到,由于string1为空字符串,所有or表达式需要继续向后看,string2不为空,由此该or表达式的值可以确定为真了,于是不再向后判断,直接就将string2的值赋给non_null,而并不是将true赋值给non_null。
这里还有一点需要说明,和C语言不同,Python的表达式中不允许进行赋值,你可能会对此充满怨言,但这也可以避免一个问题:不会像C语言那样出现将==写出=的情况。
在官方文档中,本节的最后还介绍了有关不同类型间比较的问题,不过正像官方文档所说的那样,虽然不同类型的对象间可以比较,不过我们还是不应该依赖这个,因为在未来这个特性可能会发生改变,所以这里就不作详细介绍了。