全部博文(370)
分类:
2011-10-09 01:29:30
下面我们用例子来介绍Python的基本用法。在例子中,用户输入和系统输出靠有没有提示(>>>和...)来分别。如果要试这些例子的话,需要键入提示后的所有命令,例子中没有提示的行是系统的输出。注意只有次提示的行意味着需要键入一个空行,这用于结束多行命令。
3.1 用Python作计算器使用
启动解释程序,等待主提示>>>出现。解释程序可以作为计算器使用。键入一个表达式,解释程序就可以输出结果。表达式的写法很直观:+,-,*,/, %, **等算符的作用和其它大多数语言(如Pascal或C)没什么差别,括号可以用来组合。例如:
>>> 2+2 4 >>> # 这是一个注释 ... 2+2 4 >>> 2+2 # 和代码在同一行的注释 4 >>> (50-5*6)/4 5 >>> # 整数除法得下面的整数 ... 7/3 2 >>> 7/-3 -3 >>>
和C中一样,等于号用来给变量赋值,赋值的结果不显示:
>>> width = 20 >>> height = 5*9 >>> width * height 900 >>>可以同时给几个变量赋同一个值:
>>> x = y = z = 0 # 把 x, y 和 z赋零 >>> x 0 >>> y 0 >>> z 0 >>>Python完全支持浮点数,混合类型的运算会把整数先转换成浮点数:
>>> 4 * 2.5 / 3.3 3.0303030303 >>> 7.0 / 2 3.5 >>>Python也提供了复数,方法是用j和J作为虚数单位,如1+1j,3.14e-10j,等等。
3.2. 字符串 Python除处理数字外还可以处理字符串,字符串用单撇号或双撇号包裹: >>> 'spam eggs' 'spam eggs' >>> 'doesn\'t' "doesn't" >>> "doesn't" "doesn't" >>> '"Yes," he said.' '"Yes," he said.' >>> "\"Yes,\" he said." '"Yes," he said.' >>> '"Isn\'t," she said.' '"Isn\'t," she said.' >>>字符串输出格式与输入的样子相同,都是用撇号包裹,撇号和其它特殊字符用用反斜杠转义。如果字符串中有单撇号而没有双撇号则用双撇号包裹,否则应该用单撇号包裹。后面要介绍的print语句可以不带撇号或转义输出字符串。
字符串可以用+号连接起来,用*号重复:
>>> word = 'Help' + 'A' >>> word 'HelpA' >>> '<' + word*5 + '>' '字符串可以象在C中那样用下标索引,字符串的第一个字符下标为0。
Python没有单独的字符数据类型,一个字符就是长度为一的字符串。象在Icon语言中那样,可以用片段(slice)记号来指定子串,片段即用冒号隔开的两个下标。
>>> word[4] 'A' >>> word[0:2] 'He' >>> word[2:4] 'lp' >>>片段有很好的缺省值:第一下标省略时缺省为零,第二下标省略时缺省为字符串的长度。
>>> word[:2] # 前两个字符 'He' >>> word[2:] # 除前两个字符串外的部分 'lpA' >>>注意s[:i] + s[i:] 等于 s 是片段运算的一个有用的恒等式。
>>> word[:2] + word[2:] 'HelpA' >>> word[:3] + word[3:] 'HelpA' >>>不合理的片段下标可以很好地得到解释:过大的下标被换成字符串长度,上界小于下界时返回空串。
>>> word[1:100] 'elpA' >>> word[10:] '' >>> word[2:1] '' >>>下标允许为负数,这时从右向左数。例如:
>>> word[-1] # 最后一个字符 'A' >>> word[-2] # 倒数第二个字符 'p' >>> word[-2:] # 最后两个字符 'pA' >>> word[:-2] # 除最后两个字符外的部分 'Hel' >>>但要注意的是 -0 实际还是 0,所以它不会从右向左数!
>>> word[-0] # (因为 -0 等于 0) 'H' >>>超出范围的片段下标被截断,但在非片段的情况下不要这样:
>>> word[-100:] 'HelpA' >>> word[-10] # 错误 Traceback (innermost last): File "记住片段意义的最好方法是把下标看成是字符 之间的点,第一个字符的左边界号码为0。有n个字符的字符串的最后一个字符的右边界下标为n,例如:
+---+---+---+---+---+ | H | e | l | p | A | +---+---+---+---+---+ 0 1 2 3 4 5 -5 -4 -3 -2 -1第一行数字给出字符串中下标0到5的位置,第二行给出相应的负下标。从i到j的片段由在边界i和j之间的字符组成。
对于非负下标,如果下标都在界内,则片段的长度为下标的差。例如,word[1:3] 的长度为 2。
内置函数len()返回字符串的长度:
>>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34 >>>多行的长字符串也可以用行尾反斜杠续行,续行的行首空白不被忽略,如
hello = "This is a rather long string containing\n\ several lines of text just as you would do in C.\n\ Note that whitespace at the beginning of the line is\ significant.\n" print hello结果为
This is a rather long string containing several lines of text just as you would do in C. Note that whitespace at the beginning of the line is significant.
对于特别长的字符串(比如包含说明的几段文字),如果用上面的方式每行都用\n\结尾是很麻烦的,特别是这样无法用象Emacs这样的功能强大的编辑器重新编排。对这种情况,可以使用三重撇号,例如
hello = """ This string is bounded by triple double quotes (3 times "). Unescaped newlines in the string are retained, though \ it is still possible\nto use all normal escape sequences. Whitespace at the beginning of a line is significant. If you need to include three opening quotes you have to escape at least one of them, e.g. \""". This string ends in a newline. """三重撇号字符串也可以用三个单撇号,没有任何语义差别。
多行的字符串常量可以直接连接起来,字符串常量之间用空格分隔则在编译时可以自动连接起来,这样可以把一个长字符串连接起来而不需要牺牲缩进对齐或性能,不象用加号连接需要运算,也不象字符串串内的换行其行首空格需要保持。
3.3 列表Python中有几种复合数据类型,用来把其它值组合到一起。其中最灵活的是列表,可以写成在方括号之间用逗号隔开的若干值(项)。列表的项不必取同一类型。
>>> a = ['spam', 'eggs', 100, 1234] >>> a ['spam', 'eggs', 100, 1234] >>>象字符串下标那样,列表下标从0开始,列表可以取片段,可以连接,等等:
>>> a[0] 'spam' >>> a[3] 1234 >>> a[-2] 100 >>> a[1:-1] ['eggs', 100] >>> a[:2] + ['bacon', 2*2] ['spam', 'eggs', 'bacon', 4] >>> 3*a[:3] + ['Boe!'] ['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!'] >>>与字符串不同的是列表是可变的,可以修改列表的每个元素:
>>> a ['spam', 'eggs', 100, 1234] >>> a[2] = a[2] + 23 >>> a ['spam', 'eggs', 123, 1234] >>>也可以给一个片段重新赋值,这甚至可以改变表的大小:
>>> # 替换若干项: ... a[0:2] = [1, 12] >>> a [1, 12, 123, 1234] >>> # 去掉若干项: ... a[0:2] = [] >>> a [123, 1234] >>> # 插入若干项: ... a[1:1] = ['bletch', 'xyzzy'] >>> a [123, 'bletch', 'xyzzy', 1234] >>> a[:0] = a # 在开头插入自身 >>> a [123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234] >>>内置函数也使用于列表:
>>> len(a) 8 >>>可以建立嵌套列表(表的元素也是列表),如:
>>> q = [2, 3] >>> p = [1, q, 4] >>> len(p) 3 >>> p[1] [2, 3] >>> p[1][0] 2 >>> p[1].append('xtra') # 列表方法 >>> p [1, [2, 3, 'xtra'], 4] >>> q [2, 3, 'xtra'] >>>注意这个例子中p[1]和q实际是同一个对象!也就是说它们只不过是同一个东西的两个名字(引用)而已。
3.4 编程初步Python当然不是只能用来把两个数加到一起,它可以完成很复杂的工作。例如,我们可以写出Fibonacci序列的开始几个:
>>> # Fibonacci 序列: ... # 两个元素的和定义下一个 ... a, b = 0, 1 >>> while b < 10: ... print b ... a, b = b, a+b ... 1 1 2 3 5 8 >>>这个例子介绍了几个新特色。
第一行包含一个多重赋值: 变量a和b同时得到新值0和1。在最后一行又用了多重赋值,我们可以看出赋值时先把右边都算出后再进行赋值。
while循环当循环条件(这里即: b < 10)成立时不断执行。在Python中和C中一样,非零整数值为真值,零为假值。条件也可以是字符串或列表或任何序列,长度为非零的为真,空序列为假。例子中所用的是一个简单比较。标准的比较算符和C一样:
<, >, ==, <=, >= 和 !=。循环体是缩进的:缩进是Python用来组合语句的方式。Python目前还不能提供智能自动缩进,所以你需要自己为每个缩进行键入制表符或空格。实际使用中你可以用文本编辑程序为Python 准备复杂的输入,多数文本编辑程序都有自动缩进的功能。在交互输入复合语句时必修附加一个空行以指示复合语句的完成(因为解释程序无法猜到哪是语句的最后一行)。print语句显示后面的表达式值。这和直接写出表达式不同,它可以显示多个表达式和字符串,而且可以用于程序文件中。显示时字符串没有撇号,各项目之间插入一个空格,所以你可以以精美的格式显示,如:
>>> i = 256*256 >>> print 'The value of i is', i The value of i is 65536 >>>在尾部写一个逗号可以避免最后换行:
>>> a, b = 0, 1 >>> while b < 1000: ... print b, ... a, b = b, a+b ... 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>>注意如果前一行没有结束的话系统在显示提示之前先换行。
Python还提供了和C语言一样的printf格式的输出方式,这是用%实现的,左边是格式,如:
>>> print 'The value of 1/7 is approximately %5.3f.' % 0.142857 The value of 1/7 is approximately 0.143. >>>如果有多个需要输出的项百分号右边的项可以是一个序组,如
>>> print "Name: %-10s Age: %3d" % ("White", 31) Name: White Age: 31 第四章 流程控制前面我们已经见到了如何由用while结构控制流程运行。这一章我们介绍更多的控制结构。Python具有和其它语言类似的控制结构但略有差别。
4.1 If 语句If 语句可能是最基本的程序分支语句了。例如:
>>> if x < 0: ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ...可以有零到多个elif部分,else部分可选。关键字elif是else if的缩写,这样可以缩短语句行长度。其它语言中switch 或 case 语句可以用if...elif...elif...语句组来实现。
4.2 for 语句Python中的for语句与你可能熟悉的C或者Pascal中的相应语句略有不同。不象Pascal 那样总是对数字序列进行循环,也不是象C中那样完全由程序员自由地控制循环条件和循环体,Python的for循环是对任意种类的序列(如列表或字符串)按出现次序遍历每一项。例如:
>>> # 计算字符串长: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12 >>>尽量不要在循环体内修改用来控制循环的序列(当然,只有可变的序列类型如列表才有可能被修改),这样程序可能会出问题。如果需要这样,比如说要复制某些项,可以用序列的副本来控制循环。片段记号让你很容易生成副本:
>>> for x in a[:]: # 生成整个列表的片段副本 ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate'] >>>结果是把列表中长度超过6个字符的字符串插入到列表开头。
4.3 range() 函数如果确实需要对一列数字进行循环的话,可以使用内置函数range()。它生成包含数字序列的列表,如:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>>注意给出的终点永远不出现在生成的列表中,range(10)生成一个十个数的列表,恰好是长度为10的序列的合法下标的各个值。也可以指定不同的起始点,或者指定不同的间隔(甚至负数):
>>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70] >>>为了对序列的下标进行循环,如下联合使用range() 和 len():
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb >>> 4.4 break语句,continue语句和循环中的else子句如同C语言一样,break语句跳出其所处的最内层的for 或 while循环,continue语句继续下一循环步。
循环语句还可以带一个 else 子句,当循环正常结束时执行其内容,但如果循环是用break 语句跳出的则不执行其内容。下例说明了这种用法,此例求素数:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', x, '*', n/x ... break ... else: ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3 >>> 4.5 pass 语句pass语句不执行任何操作,当语法要求一个语句而程序不需要执行操作时就用此语句。例如:
>>> while 1: ... pass # 等待键盘中断 ... 4.6 函数定义我们可以定义一个函数用来计算某一界限以下的所有Fibonacci序列值:
>>> def fib(n): # 写出 n 以下的所有Fibonacci序列值 ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # 调用刚刚定义的函数: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 >>>其中关键字 def 开始一个函数定义,其后应该是函数名,括号内的形参表,以冒号结束。构成函数体的各语句从下一行开始,用一个制表符缩进。函数的第一个语句可以是一个字符串,如果是的话,这个字符串就是函数的文档字符串,简称为docstring。有一些工具可以利用文档字符串自动生成可打印的文档,或者让用户交互地浏览代码,所以在自己编程时加入文档字符串是一个好习惯,应该养成这样的习惯。
函数在执行时对局部变量引入一个新的符号表。函数中的变量赋值都存入局部符号表;引用变量时变量名先从局部符号表中查找,然后在全局符号表中查找,最后从内置的名字中查找。因此,在函数中不能直接对全局变量赋值(除非用了global语句来说明),但可以引用全局变量的值。
函数调用的实参被引入函数的局部符号表,即函数的参数是按值调用的。函数再调用其它函数时为该函数生成一个新的符号表。但是严格地说,函数的调用是按引用调用的,因为如果参数是一个可变类型如列表的话在函数中改变形参的内容将导致实参的内容被改变(不改变的是实参名字的绑定关系)。
函数定义把函数名放入当前符号表。函数名的值类型为用户自定义函数,这个值可以赋给另一个名字,从而这个名字也代表相同的函数。这可以作为一般的改名方法:
>>> fib你可能会说 fib 不是函数而是过程。Python和C一样,过程只是不返回值的函数。实际上,严格地说,过程也返回一个值,只不过是一个很没意思的值。这个值叫做 None(这是一个内置的名字)。解释程序交互运行时如果只需要显示这个值的话就会忽略不显示。如果希望显示的话可以用 print 语句:
>>> print fib(0) None >>> 也可以写一个函数返回Fibonacci 序列的数值列表而不是显示这些值: >>> def fib2(n): # 返回直到n的Fibonacci 序列值 ... result = [] ... a, b = 0, 1 ... while b < n: ... result.append(b) # 解释见下面 ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # 调用 >>> f100 # 输出结果 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>>这个例子也演示了新的Python特色:return语句从函数中退出并返回一个值。不带返回值的return可以从过程中间退出,运行到过程的末尾也可以退出,这两种情况下返回None。
语句result.append(b)调用列表对象result的一个方法。方法是“属于”一个对象的函数,引用格式为obj.methodname,其中obj是某个对象(也允许是一个表达式), methodname 是由该对象的类型定义的一个方法的名字。不同的不同的方法。不同类型的方法可以使用相同的名字而不致引起误解。(可以定义自己的对象类型和方法,使用类,本文后面会讨论这个话题)。例子中的append()方法时列表对象的方法,它在列表末尾增加一个新元素。在本例中这等价于“result = result + [b]”,只是更有效。
4.7 函数参数可以定义使用可变个数参数的函数。这样的定义方法有三种,可以联合使用。
4.7.1 参数缺省值可以为一个参数或几个参数指定缺省值。这样定义的函数在调用时实参个数可以比定义时少。例如:
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while 1: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return 1 if ok in ('n', 'no', 'nop', 'nope'): return 0 retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint这个函数在调用时既可以这样调用:ask_ok('Do you really want to quit?'),或者可以这样调用:ask_ok('OK to overwrite the file?', 2)。缺省值是在函数定义时的定义作用域中计算的,所以例如:
i = 5 def f(arg = i): print arg i = 6 f()将显示5。
注意:缺省值只计算一次。当缺省值是可变对象如列表或字典时这一点是要注意的。例如,以下函数会在以后的调用中累加它的值:
def f(a, l = []): l.append(a) return l print f(1) print f(2) print f(3) This will print [1] [1, 2] [1, 2, 3]如果你不希望缺省值在连续的调用中被保留,可以象下面这样改写函数:
def f(a, l = None): if l is None: l = [] l.append(a) return l 4.7.2 关键字参数函数调用时也可以象“关键字 = 值”这样指定实参,其中关键字是定义时使用的形参的名字。例如:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "Volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!"可以用如下几种方式调用:
parrot(1000) # 缺省值 parrot(action = 'VOOOOOM', voltage = 1000000) # 关键字,缺省值,次序可变 parrot('a thousand', state = 'pushing up the daisies') # 位置参数,缺省值,关键字 parrot('a million', 'bereft of life', 'jump') # 位置参数,缺省值但以下几种调用方式是错误的:
parrot() # 非缺省的参数没有提供 parrot(voltage=5.0, 'dead') # 关键字参数后面又出现了非关键字参数 parrot(110, voltage=220) # 参数值重复提供 parrot(actor='John Cleese') # 未知关键字
一般说来,实参表中位置参数在前,关键字参数在后,关键字名字必须是形参名字。形参有没有缺省值都可以用关键字参数的形式调用。每一形参至多只能对应一个实参,因此,已经由位置参数传入值的形参就不能在同一调用中再作为关键字参数。
如果形参表中有一个形为**name的形参,在调用时这个形参可以接收一个字典,字典中包含所有不与任何形参匹配的关键字参数。形参表中还可以使用一个特殊的如*name的形参,它将接受所有不能匹配的位置参数组成的一个序表。*name只能在**name之前出现。例如,如果定义了下面的函数:
def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, '?' print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print '-'*40 for kw in keywords.keys(): print kw, ':', keywords[kw]就可以象下面这样调用:
cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese', shopkeeper='Michael Palin', sketch='Cheese Shop Sketch')结果显示:
-- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch 4.7.3 任意个数参数在所有有名的形参的后面可以有两个特殊的形参,一个以*args的形式命名,一个以**kw 的形式命名。有了*args形式的形参后函数在调用时就可以在正常的能匹配的实参表后面输入任意个数的参数,这些参数组成一个序表赋给args形参,不能匹配的关键字参数组成一个字典赋给kw形参。在任意个数形参之前可以有0到多个正常的参数。例如:
def fprintf(file, format, *args): file.write(format % args) 4.7.4 Lambda形式因为许多人的要求,Python中加入了一些在函数编程语言和Lisp中常见的功能。可以用lambda 关键字来定义小的无名函数。这是一个返回其两个参数的和的函数:“lambda a, b: a+b” 。Lambda形式可以用于任何需要函数对象的地方。从句法上讲lambda形式局限于一个表达式。从语义上讲,这只是正常的函数定义的句法甜食。像嵌套函数定义一样,lambda形式不能访问包含其定义的作用域中的变量,但审慎地使用缺省参数之可以绕过这个限制。例如:
def make_incrementor(n): return lambda x, incr=n: x+incr 4.7.5 文档字符串关于文档字符串的内容与格式正在形成一些惯例。第一行应该为简短的对象目的概括说明。为了简明起见,这一行不应该提及对象的名字或类型,因为这些可以通过其他途径得知(当然如果对象名字就是一个描述函数操作的动词则当然可以提及其名字)。着以行应该用大些字母开始,以句点结尾。如果文档字符串中有多行,第二行应该是空行,把概括说明与其它说明分开。以下的行可以是一段或几段,描述对象的调用方法,它的副作用,等等。
Python的扫描程序不会从多行字符串中去掉缩进空白,所以处理文档的工具需要自己处理缩进。只要遵循如下的惯例就可以有利于缩进空白的处理。在第一行之后的第一个非空白的行决定整个文档字符串的缩进数量(我们不用第一行,因为它经常是直接跟在表示字符串开始的引号后面)。文档字符串中除第一行以外的各行都要删除等价于此行的缩进量的空白。对制表符将扩展为空格后再删除。
第五章 Python数据结构
本章更详细地讨论一些已经讲过的数据类型的使用,并引入一些新的类型。
5.1 列表列表数据类型还有其它一些方法。下面是列表对象的所有方法:
下例使用了所有的列表方法:
>>> a = [66.6, 333, 333, 1, 1234.5] >>> print a.count(333), a.count(66.6), a.count('x') 2 1 0 >>> a.insert(2, -1) >>> a.append(333) >>> a [66.6, 333, -1, 333, 1, 1234.5, 333] >>> a.index(333) 1 >>> a.remove(333) >>> a [66.6, -1, 333, 1, 1234.5, 333] >>> a.reverse() >>> a [333, 1234.5, 1, 333, -1, 66.6] >>> a.sort() >>> a [-1, 1, 66.6, 333, 333, 1234.5] 5.1.1 函数程序设计工具Python中有一些函数程序设计风格的东西,例如前面我们看到的lambda形式。关于列表有三个非常有用的内置函数:filter(), map()和reduce()。
“filter(函数, 序列)”返回一个序列(尽可能与原来同类型),序列元素是原序列中由指定的函数筛选出来的那些,筛选规则是“函数(序列元素)=true”。filter()可以用来取出满足条件的子集。例如,为了计算一些素数:
>>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23]“map(函数,序列)”对指定序列的每一项调用指定的函数,结果为返回值组成的列表。map() 可以对序列进行隐式循环。例如,要计算三次方,可用:
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]可以有多个序列作为自变量,这时指定的函数必须也有相同个数的自变量,函数从每个序列分别取出对应元素作为自变量进行调用(如果某个序列比其它的短则取出的值是None)。如果指定的函数是None,map()把它当成一个返回自己的自变量的恒同函数。在函数用None的情况下指定多个序列可以把多个序列搭配起来,比如“map(None, list1, list2)”可以把两个列表组合为一个成对值的列表。见下例:
>>> seq = range(8) >>> def square(x): return x*x ... >>> map(None, seq, map(square, seq)) [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]“reduce(函数, 序列)”用来进行类似累加这样的操作,这里的函数是一个两个子变量的函数,reduce()先对序列的前两项调用函数得到一个结果,然后对结果和序列下一项调用函数得到一个新结果,如此进行到序列尾部。例如,要计算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 5.2 del语句上面我们看到,列表的remove()方法可以从列表中删去某个取值的项,我们还可以用del 语句来删除指定下标的项。也可以用del语句从列表中删除一个片断(前面我们是用给片断赋空列表的办法删除片断的)。例如:
>>> a [-1, 1, 66.6, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.6, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.6, 1234.5]del也可以用来删除整个变量,例如:
>>> del a
变量删除以后再引用该变量就会出错(除非又给它赋值了)。后面我们还会看到del的其它一些应用。
5.3 序表和序列我们看到列表和字符串有许多共同点,例如,下标和片断运算。它们都属于序列数据类型。因为Python是一个正在不断发展的语言,以后还可能会加入其它的序列数据类型。现在还有一种标准的序列数据类型,称为序表(tuple)。
序表由一系列值用逗号分隔而成,例如:
>>> t = 12345, 54321, 'hello!' >>> t[0] 12345 >>> t (12345, 54321, 'hello!') >>> # 序表允许嵌套: ... u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))输出的序表总是用括号包围,这样可以保证嵌套序表得以正确解释。输入时可以有括号也可以没有括号,当经常是必须有括号(如果序表是一个大表达式的一部分)。
序表有许多用处,例如,(x,y)坐标对,数据库中的职工纪录,等等。序表与字符串一样是不可变的:不允许对序表的某一项赋值。
生成序表时对0项或1项的序表有特殊的规定:空序表用一对空括号表示;只有一项的序表用一个之后面跟一个抖好表示(指把这个值放在括号内是不够的)。这样写不够美观,但很有效。例如:
>>> empty = () >>> singleton = 'hello', # <-- note trailing comma >>> len(empty) 0 >>> len(singleton) 1 >>> singleton ('hello',)语句t = 12345, 54321, 'hello!'是序表打包的一个实例:12345, 54321和'hello!'这些值被打包进了一个序表中。相反的操作也是允许的,例如:
>>> x, y, z = t
这叫做序表解包。序表解包要求等号左边的变量个数等于序表的长度。注意多重赋值只是序表打包和序表解包的联合使用。有时也对列表进行类似操作,即列表解包。只要把各变量写成一个列表就可以进行解包:
>>> a = ['spam', 'eggs', 100, 1234] >>> [a1, a2, a3, a4] = a 5.4 字典Python内置的另一个有用的数据类型是字典。字典在其它语言中有时被称为“关联记忆” 或“关联数组”。字典不象序列,它不是用在一个范围之内的数字下标来索引,而是用键值来索引,键值可以是任何不可变类型。字符串和数值总可以作键值。如果序表只包含字符串、数值或序表则序表也可以作键值使用。列表不能用作键值,因为列表可以用其append()方法就地改变值。
最好把字典看成是一系列未排序的“键值:值”的集合,在同一字典内键值是互不相同的。一对空大括号产生一个空字典:{}。在大括号内加入用逗号分开的“键值:值”对可以在字典内加入初始的键值和值对,字典在输出时也是这样显示的。对字典的主要操作是以某个键值保存一个值,以及给定键值后查找对应的值。也可以用del删除某个键值:值对。如果用一个已有定义的键值保存某个值则原来的植被遗忘。用不存在的键值去查找会出错。
字典对象的keys()方法返回字典中所有键值组成的列表,次序是随机的。需要排序时只要对返回的键值列表使用sort()方法。为了检查某个键值是否在字典中,使用字典的has_key() 方法。
下面是字典使用的一个简单例子:
>>> 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'] >>> tel.has_key('guido') 1 5.5 条件的进一步讨论在while语句和if语句中使用的条件除了可以使用比较之外还可以包含其它的运算符。比较运算符“in”和“not in”可以检查一个值是否在一个序列中。运算符“is”和“is not ”比较两个对象是否恰好是同一个对象,这只对象列表这样的可变对象有意义。所有比较运算优先级相同,而比较运算的优先级比所有数值运算优先级低。
比较允许连写,例如,a < b == c检查是否a小于等于b而且b等于c。
比较可以用逻辑运算符and和or连接起来,比较的结果(或其它任何逻辑表达式)可以用not 取反。逻辑运算符又比所有比较运算符低,在逻辑运算符中,not优先级最高,or的优先级最低,所以“A and not B or C”应解释为“(A and (not B)) or C”。当然,可以用括号来表示所需的组合条件。
逻辑运算符and和or称为“短路”运算符:运算符两侧的表达式是先计算左边的,如果左边的结果已知则整体结果已知就不再计算右边的表达式。例如,如果A和C为真而B为假则“A and B and C”不会计算表达式C。一般地,当短路运算符的运算结果不是用作逻辑值的时候返回的是最后求值的那个表达式的值。
可以把比较或其它逻辑表达式的结果赋给一个变量。例如:
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim'注意Python和C不同,表达式中不能进行赋值。
5.6 序列与其它类型的比较序列对象可以和其它同序列类型的对象比较。比较使用字典序:先比较最前面两项,如果这两项不同则结果可以确定;如果这两项相同,就比较下面的两项,如此下去,直到有一个序列到头为止。如果某两项本身也是同类型的序列,则进行递归的字典序比较。如果两个序列的所有各项都相等,则这两个序列相等。如果一个序列是另一个序列的一个初始子序列,短的一个是较小的一个。字符串的字典序比较按各个字符的ASCII次序进行。下面是一些序列比较的实例:
(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)注意不同类型的对象比较目前也是合法的。结果是确定的但却没有什么意义:不同类型是按类型的名字排序的。所以,列表(list)总是小于字符串(string),字符串总是小于序表(tuple),等等。但是程序中不能依赖这样的比较规则,语言实现可能会改变。不同的数值类型可以按数值来比较,所以0等于0.0,等等。