文章目錄
- 4.7.1 參數的預設值
- 4.7.2 關鍵字參數
- 4.7.3 任意參數列表
- 4.7.4 解壓參數列表
- 4.7.5 lambda形式
4.1 if語句
也許大家最熟悉的語句類型就是if語句。例如:
可以有零到多個elif部分,else部分是可選的。關鍵字elif是對else if的簡寫,在避免過多的縮排方面是有用的。一個if...elif...elif...序列是對其它語言裡的switch或case語句的一種替換。
4.2 for語句
Python裡面的for語句和C或Pascal裡面的有點不同。它不總是在數位算數序列上進行迭代(像Pascal),或使使用者有能力定義迭代步驟和停止條件(像C),Python的for語句可以在任何序列(列表或字串)上迭代,按照它們出現在序列中的順序。例如:
在迴圈裡面修改正在被迭代的序列(只可能是可修改的序列類型,像列表)不是安全的。如果你想修改正在迭代的序列(例如,重複當前的選中項),你必須在一個拷貝上迭代。切片操作可以特別方便的獲得序列的拷貝:
4.3 range()函數
如果你需要在一個數字序列上迭代,內建函數range()就在手邊,它產生算數序列:
給出的結束點絕不會包含在序列裡,range(10)產生10個值,這些值是長度為10的序列的所有項的合法索引值。可以讓range從另一個數字開始,或指定一個不同的增量(可以是負值,有時候這個增量被稱為步長):
想要在一個序列的索引上進行迭代,可以結合range()和len()來使用:
在大多數這樣的情況,使用enumerate()函數非常方便。
當你僅僅是列印一個range,會發生一個奇怪的事情:
在許多方面,range()返回的對象的行為就像一個列表,事實上它不是。它是一個對象,當你在它上面迭代時,它會返回期望序列的連續的項,它並不真的產生一個列表,這樣可以節省空間的。
我們稱這樣的一個對象是可迭代的,適合作為函數和構造的目標,從這些函數和構造希望獲得連續的項直到這些項全部耗盡。我們已經看到for語句就是這樣一個迭代器,list()函數是另一個,它從可迭代的對象建立列表:
稍後我們將看到更多返回可迭代對象的函數和使可迭代對象作為參數的函數。
4.4 break和continue語句,迴圈的else從句
break語句,和C裡差不多,終止最小的封閉的for或while迴圈。
迴圈語句可以有一個else從句,這個從句是在迴圈是通過列表耗盡而終止(for語句)或迴圈條件變為false(while語句)時執行,當迴圈是通過break語句終止時並不執行。下面的迴圈就是它的典型,尋找質數:
(這是正確的代碼。esle從句屬於for迴圈,而不是if語句。)
當用於迴圈時,else從句與if語句的else從句相比,它和try語句的else從句有更多的共同之處。try語句的else從句當沒有異常發生時執行,迴圈的else從句當沒有break發生時執行。
continue語句,也是從C裡面照搬過來的,停止本次迴圈,繼續下次迴圈:
4.5 pass語句
pass語句什麼都不做,它適於用當從文法上講要求有一個語句,但是從程式來講不需要執行動作。例如:
它通常用於建立最小化的類:
另一個pass可以使用的地方是作為函數的預留位置或者當你寫新代碼時的條件體,允許你在更抽象的層級思考。pass語句會被安靜的忽略:
4.6 定義函數
我們可以建立一個函數來輸出任意邊界的斐波那契序列:
關鍵字def表明這是一個函數定義。它後面必須跟一個函數名稱和括弧括起來的形式參數列表。從下一行開始,語句構成了函數體,它們必須縮排。
函數體的第一條語句可選為一個字串字面量,這個字串字面量是函數的文檔字串。有一些工具使用這些文檔字串自動產生線上的或列印的文檔,或讓使用者互動的通過代碼瀏覽,當你寫代碼的時候加上文檔字串是一個很好的實踐,並使它成為一種習慣。
函數的執行引進一個新的符號表被函數的本地變數使用。更加準確的說,一個函數裡所有的變數賦值都把值儲存到了本地符號表,然後變數引用首先搜尋本地變數表,然後封閉函數的本地變數表,然後全域符號表,最後內建名稱表。因此,全域變數不能在一個函數裡面直接被賦值(除非被命名在一個global語句中),雖然它們可以被引用到。
當一個函數被調用時,這個函數調用的實際參數被引入到被調函數的本地符號表,因此,參數是通過傳值傳遞的(這個值總是對象引用,不是對象的值)。當一個函數調用另一個函數時,一個新的本地符號表被建立為了那個調用。
函數定義把函數名稱引入到當前符號表。函數名稱的值有一個類型,這個類型被解譯器作為使用者定義函數來認知。這個值可以被賦給另外一個名稱,它也被作為函數使用。它是由通用命名機制實現的:
對於其它語言來說,fib對象不是一個函數,而是一個過程,因為它不傳回值。事實上,即使函數沒有一個return語句也會返回一個值,即使是一個無聊的值。這個值叫做None(這個一個內建的名字)。寫入值None通常會被解譯器阻止,如果它是唯一被寫的值。如果你真的想看它的話就使用print():
寫一個函數把斐波那契序列作為列表返回非常簡單,而不是列印它:
這個樣本示範了一些Python新特性:
- return語句從函數返回一個值。return後面如果沒有跟運算式就返回None。如果沒有到函數結束的話也返回None。
- 語句result.append(a)調用了列表對象result的一個方法。一個方法就是一個函數,這個函數屬於一個對象,被命名為obj.methodname,這裡的obj是某個對象(可以是一個運算式),methodname是被這個物件類型定義的一個方法的名字。不同的類型定義不同的方法。不同類型的方法可以擁有同樣的名字,不會因此歧義。樣本裡面的append()方法是為列表對象定義的,它在列表的末尾添加一個新元素。在這個樣本裡面它等同於result = result + [a],但是更有效。
4.7 更多有關定義函數
也可以定義有可變數目參數的函數。參數有三種形式,它們可以結合在一起。
4.7.1 參數的預設值
最有用的形式是為一個或多個參數指定預設值。這樣建立的函數在調用時可以傳入比定義時更少的參數。例如:
這個函數可以以幾種方式調用:
- 只給出必須的參數:ask_ok('Do you really want to quit?')
- 給出其中一個選擇性參數:ask_ok('OK to overwrite the file?', 2)
- 給出全部的參數:ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
這個樣本也介紹了in關鍵字,來測試一個序列是否包含一個確定的值。
這些預設值在函數定義的時候被計算,是在定義的範圍中。所以:
將列印5。
重要警告:預設值只被計算一次。當預設值是一個可變對象時會有一個不同之處,如列表,字典或許多類的執行個體。下面的函數在後續的調用中會累積傳給它的參數:
這將列印:
如果你不想這些預設的參數在後續的調用中共用,你可以像這樣來實現函數:
4.7.2 關鍵字參數
函數也可以使用kwarg=value這種形式的關鍵字參數進行調用。例如,下面這個函數:
接收一個必填的參數(vltage)和三個可選的參數(state,action,和type)。可以使用下面的任何一種方式調用:
但是下面的調用都是非法的:
在一個函數調用中,關鍵字參數必須跟在位置參數後面。所有被傳進去的關鍵字參數必須匹配這個函數接收參數中的一個(actor對函數parrot是一個非法的參數),它們的順序並不重要。這同樣包括非選擇性參數(parrot(voltage=1000)是合法的)。沒有參數可以多次接收一個值。這個樣本是失敗的由於這個約束:
當最後一個形式參數是以**name這種形式出現的,它將接收一個字典包含所有的除了那些形式參數以外的所有關鍵字參數。它可以和*name這種形式的形式參數結合起來,它接收一個元祖包含超出形式參數以外的所有位置參數。*name必須在**name前面。例如,如果我們定義一個函數像這樣:
它可以像這樣被調用:
當然,它將列印:
注意,關鍵字參數名稱的列表是在列印出它們的內容前通過對關鍵字字典的keys()方法的結果進行排序而建立的;如果不這樣做的話,列表裡面的參數被列印的順序是沒有定義的。
4.7.3 任意參數列表
最後,使用頻率最少的是一個函數可以使用任意數目的參數進行調用。這些參數將被封裝在一個元祖裡面。在這些可變數目參數之前,可以有零或多個形式參數:
通常,這些可變參數都在形參列表的最後面,因為它們收集所有傳入函數的剩餘的輸入參數。出現在*args後面的任何形式參數只能是關鍵字參數,意味著它們只能用作關鍵字參數而不是位置參數:
4.7.4 解壓參數列表
當參數已經在一個列表裡或元祖裡,但是函數調用需要解壓它們成為單獨的位置參數,這是相反的情況就發生了。例如,內建range()函數希望單獨的開始和結束參數。如果它們不能單獨的得到,函數調用時使用*操作符來把參數從列表或元祖中解壓出來:
以同樣的方式,字典可以使用**操作符來分發關鍵字參數:
4.7.5 lambda形式
通過福士需求,很少的一些通常在函數式程式設計語言(像Lisp)裡被發現的新特性已經被添加到Python裡。使用lambda關鍵字,很小的匿名函數可以被建立。這是一個返回它的兩個參數之和的函數:lambda a, b: a+b。lambda形式可以應用在任何要求函數對象的地方。它們在文法上限制為一個單一的運算式。在語義上,它們僅僅是正常函數定義的文法糖。像嵌套函數定義,lambda形式可以引用來自於包含它的範圍裡面的變數:
本文是對官方網站內容的翻譯,原文地址:http://docs.python.org/3/tutorial/controlflow.html