Python程式設計入門(3) (轉)

worldblog發表於2007-12-07
Python程式設計入門(3) (轉)[@more@]

第四章 流程控制

前面我們已經見到了如何由用while結構控制流程執行。這一章我們介紹更多的控制結構。具有和其它語言類似的控制結構但略有差別。

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 >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89 >>>  


你可能會說 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, **keys): 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的掃描程式不會從多行字串中去掉縮排空白,所以處理文件的工具需要自己處理縮排。只要遵循如下的慣例就可以有利於縮排空白的處理。在第一行之後的第一個非空白的行決定整個文件字串的縮排數量(我們不用第一行,因為它經常是直接跟在表示字串開始的引號後面)。文件字串中除第一行以外的各行都要刪除等價於此行的縮排量的空白。對製表符將擴充套件為空格後再刪除。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989379/,如需轉載,請註明出處,否則將追究法律責任。

相關文章