4更多的控制工具
除了剛介紹的while語句,Python還有和其它程序寵類似的控制流語句和一些變種.
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語句在序列(list或者string,以及更多)的元素上迭代.迭代以元素在序列中的順序進行.例如:
改變正在迭代的序列是不安全的(這種情況只會發生在可變序列,如列表上).如果需要修改正在迭代的列表(例如,複製選中的元素),你必須在序列的一個拷貝上迭代.切片表示使這一切變得很方便:
4.3 range() 函數
如果需要在數字序列上迭代,內置函數range()是很好的選擇.它產生包含算術數列的列表:
給出的終點不是列表的一部分. range(10)
產生的列表包含了長度爲10的序列的合法下標.可以讓range從一個非零數開始生成序列,或者改變遞增間隔,間隔甚至可以爲負
:
可以組合range()和len()實現在序列下標上的迭代:
4.4 break 和continue 語句,以及循環中的else語句
break語句和C中類似,從內層的for或者while循環中跳出.
continue 語句同樣來源於C, 開始循環中的下一個迭代.
循環語句也可以擁有一個else部分;當列表結束(for語句)或者條件爲假(while語句)時就會執行else部分.但循環以break終止時不會執行else部分.下面這個尋找素數的例子可以說明這一點:
4.5 pass 語句
Pass語句不作任何事情.當語法上需要一個語句,但程序不需要任何操作時使用pass語句.例如:
4.6 定義函數
我們可以創建一個輸出任何範圍以內Fibonacci數列的函數:
關鍵詞 def 引入一個函數定義.後面必須跟着函數名和由小括號括起的命名參數(formal parameter).函數體從下一行開始,必須有縮進.函數第一行也可以是一個字符串.這個字符串是函數的文檔字符串(document string),或docstring. 一些工具使用docstring自動產生在線或打印文檔,或者讓用戶交互瀏覽代碼.在代碼中使用docstring是一個好的實踐,就讓它成爲你的一個習慣吧.
函數的執行引入一個新的包含局部變量的符號表.更準確的說,所有函數內的變量賦值都把值保存在局部符號表中。對變量的引用首先查找局部符號表,然後是全局符號表,其次是內置名稱表。因此全局變量儘管可以被引用,但不能在函數中直接賦值(除非用global關鍵字聲明)。
實參放在被調用函數的局部符號表中。因此參數是按值傳遞的(這個值總是對對象的引用,不是對象的值[1])。當一個函數調用另一個函數時,Python會爲被調用函數創建一個新的符號表。
函數定義在當前符號表中引入了函數名。函數名對應的值具有"用戶定義的函數"類型。Python解釋能識別這種類型。該值可以被賦給另一個名稱。賦值後另一個名稱也可以當函數使用。這是一種通用的重命名機制。
You might object that fib
is not a function but a procedure. In Python, like in C, procedures are just functions that don't return a value. In fact, technically speaking, procedures do return a value, albeit a rather boring one. This value is called None
(it's a built-in name). Writing the value None
is normally suppressed by the interpreter if it would be the only value written. You can see it if you really want to:
你可能會質疑說fib不是一個函數,而是一個過程。在Python中和C中一樣,過程是不返回值的函數,從技術上講,過程實際上返回了一個值,一個沒有意義的值。這個值叫做None(一個內置名稱)。如果只有一個None值需要輸出,解釋器不會輸出。如果你真的想看到返回的None值也是可以的:
It is simple to write a function that returns a list of the numbers of the Fibonacci series, instead of printing it:
這個例子和通常見到的一樣,展示了Python的一些新特性:
· return語句從函數中返回一個值。不帶表達式參數的return語句返回None。函數結尾也自動返回None.
· result.append(b)
語句調用了list對象result的一個方法。方法是屬於某個對象的函數,記作obj.methodname.
obj是某個對象,也可以是一個表達式。Methodname是該對象的類型定義的一個名稱。不同的類型擁有不同的方法。不同類型的方法可以同名而不會引起混淆.(可以使用類來定義你自己的對象類型和相關方法,見本教程稍後部分).例子中的append()方法是list類型的對象定義的。它在list的末端添加一個新的元素。本例中它相當於"result=result+[b]",但更高效.
4.7 更多關於定義函數
也可以在函數中使用可變數目的參數。有三種形式使用變數目參數的方法。可以一起應用。
4.7.1 參數的缺省值
最有用的形式是爲一個或多個參數指定缺省值。這使創建的函數可以比定義允許的要少的參數進行調用。例如:
這個函數可以用下面的任何一種方式調用:ask_ok('Do you really want to quit'),或者ask_ok('OK to overwrite the file?', 2).
這個例子還引入了關鍵字in.in用來測試一個給定的值是否在某個序列中。
缺省值在函數定義時被計算,因此:
會輸出5
下面這個例子是譯者加的,大家隨便看看也就是了。
>>> l = [1,2,3]
>>> def f(fl = l): #這裏fl被初始化爲l指向的對象。
print fl
>>> f
<function f at 0x00DB1770>
>>> f()
[1, 2, 3]
>>> l.append(4) #這時l與fl指向同一個對象,改變l指向的對象同時就改變了fl指向的對象
>>> f()
[1, 2, 3, 4]
>>> l = [2,3]
>>> f()
[1, 2, 3, 4]
>>>
重要提示:缺省值只計算一次。這使得缺省值是一個可變對象如列表,字典或者大多數類的實例時會有些許的不同。例如,下面的函數會在一系列調用中累加傳給它的參數:
會輸出
如果你不想缺省值被不同調用共享,可以這樣寫:
4.7.2 鍵值參數
函數也可以用鍵值的方式調用如"keyword=value".例如,下面的函數:
可以以以下任何一種形式調用:
但是下列調用是非法的:
總而言之,一個參數列表中按位置表示的參數必須在任何按鍵值表示的參數之前。鍵值必須從正式參數中選擇。正式參數是否有缺省值並不重要。沒有參數可以被賦值兩次—一次調用中已經按位置賦值的參數不能再用鍵值賦值。下面是一個與這種規定衝突的例子:
當最後一個正式參數用**name的形式表示時,代表一個字典。該字典包含了除了和已有的正式參數相關聯的其它所有的鍵值參數。**name還可以與一個*name形式的參數一起使用(下一節有講)。*name包含了所有不在正式列表裏的按位置表示的參數(*name一定要出現在**name以前)。例如:
可以這樣調用cheeseshop:
會輸出以下內容:
請注意鍵值參數名稱列表的 sort()方法在打印字典內容之前被調用。如果沒有調用sort(),打印參數的順序是未定義的。
4.7.3 任意的參數列表
最後提到的是最不常用的一種函數調用方式:以任意數目的參數調用函數。這些參數會被封裝到一個元組中。在這些可變數目的參數前會有0到多個普通參數。
4.7.4 解包參數列表
相反的情形是參數已經在列表或元組中,但需要解包成獨立的位置參數以滿足函數調用的要求。例如內置的range()函數需要獨立的start和stop參數。如果不能單獨得到這些參數,使用*操作符從列表或者元組中解包參數:
同理,字典也可以用**操作符解包爲鍵值形式:
**
-operator:
4.7.5 Lambda表達式
在廣泛要求下,一些函數式編程語言如Lisp的特性被加入到Python中。使用lambda關鍵字可以創建一些小的匿名函數。這裏是一個返回兩個參數之和的函數:"lambda a, b: a+b".Lambda表達式可以用在任何需要函數對象的場合。它們在語法上被限制只能使用一個表達式。語義上它們只是普通函數定義的補充。(Semantically, they are just syntactic sugar for a normal function definition.)和嵌套函數定義一樣,lambda表達式可以引用包含它的作用域的變量。
4.7.6 文檔字符串
這裏是一些新的關於文檔字符串內容和格式的慣例。
第一行是關於對象的短而精確的概括。爲簡潔明瞭,他不必詳細陳述對象的名稱或類型,因爲有其它方法完成這些任務(除了這個名字正好是一個描述函數操作的動詞)。這一行應該以大寫字母開頭而以句號結束。
如果文檔字符串不止一行,第二行應當爲空。這樣能從視覺上把概括性的語句和描述性的部分分開。後面的部分應當包括一個或多個段落以描述函數調用約定,副作用等。
Python解釋器並不會從多行字符串中刪除縮進。因此處理文檔的工具必要時需要刪除縮進。可以用下面的方式完成:文檔字符串中第二個非空行決定了整個文檔字符串的縮進量(不能使用第一行因爲它經常跟在字符串開始的引號後以致它的縮進並不能表示字符串中其他部分的縮進)。相當於這些數目的縮進被從後面的行中刪除。不應該有小於這些縮進的行。但如果真的有的話,該行所有的前導空格都會被刪除。等量的空格會在tab擴展(通常8個空格)後進行。
下面是一個多行文檔字符串的例子:
[1] 實際上,對象引用調用是一個更好的表述。因爲傳遞一個可變的對象時,對對象所做的任何修改對調用者都是可見的(如在列表中插入元素)。