1. 程式人生 > >《Python3.6官方文件》– 4.更多流程控制語句

《Python3.6官方文件》– 4.更多流程控制語句

4 更多流程控制語句

除了剛才介紹的while語句,Python也引入了其它語言常見的流程控制語法,並稍作變化。

4.1 if語句

或許最廣為人知的控制語句就是if語句。例如:

 >>> x = int(input("Please enter an integer: "))
 Please enter an integer: 42
 >>> if x < 0:
 ...     x = 0
 ...     print('Negative changed to zero')
 ... elif x == 0:
 ...     print('Zero')
 ... elif x == 1:
 ...     print('Single')
 ... else:
 ...     print('More')
 ...
 More

if語句可以有零個或者更多elif分支,else分支是非強制要求有的。關鍵詞‘elif’是比‘else if’短的,這可以有效避免過度縮排問題。而且,if … elif … elif …語句可以替換其它語言中的switch/case語句。

4.2. for Statements

Python中的for語句與你可能用過的C或者Pascal語言中的for語句有點不同。與通常通過一個等差數列進行迭代(像Pascal語言),或者給予使用者自主迭代和終止步驟(就像C語言),Python的For語句以集合(list或者string)中的元素為迭代單元,按照它們在集合中的順序逐個迭代。例如(我並沒有含沙射影):

 >>> # Measure some strings:
 ... words = ['cat', 'window', 'defenestrate']
 >>> for w in words:
 ...     print(w, len(w))
 ...
 cat 3
 window 6
 defenestrate 12

如果你需要在迭代中時修改集合(例如為集合複製某個元素),我們建議你先為集合建立副本。直接迭代集合並不能為集合建立副本,切片操作可以很方便的做到這一點。

  >>> for w in words[:]:  # Loop over a slice copy of the entire list.
  ...     if len(w) > 6:
  ...         words.insert(0, w)
  ...
  >>> words
  ['defenestrate', 'cat', 'window', 'defenestrate']

靠著使用for w in words:語法,我們可以用不斷插入defenestrate單詞,來嘗試創建出很大的集合。

4.3. range()函式

如果你需要迭代一組連續數字,內建函式range()正好可以幫上忙。它生成遞增數列:

  >>> for i in range(5):
  ...     print(i)
  ...
  0
  1
  2
  3
  4

指定的尾數入參永遠不是生成序列的一部分; range(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

如果你列印一個range函式,會發生奇怪的事情:

  >>> print(range(10))
  range(0, 10)

從很多特性上看,rang()函式返回的物件都表現的像是一個list,但實際上它不是。當你迭代它時,它返回了你想要的連續數字,但是它為了節省記憶體空間,不是個真正的list。

我們稱這種物件為可迭代的,即適合成為可以期待得到有限連續項的函式或者結構的目標。我們已經知道,for語句是一個類似的迭代器,list()函式也是一個類似的迭代器;它以可迭代物件建立list。

  >>> list(range(5))  
  [0, 1, 2, 3, 4] 

稍後我們可以看到更多函式可以返回可迭代物件,或者把可迭代物件作為入參。

4.4.迴圈中的break、continue語句和else子句

break語句,就像在C語言中一樣,跳出最內層的for或者while迴圈。

迴圈語句也許有一個else子句;它在for語句的list迴圈終結時或者while語句的條件變為false時執行,但在迴圈被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:
  ...         # loop fell through without finding a factor
  ...         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

(是的,這是一段沒有錯誤的程式碼。仔細看:else子句是屬於for迴圈,而不是if語句)

當與迴圈一起使用時,它的else子句與在try語句塊和if語句塊的else子句功能類似:當try語句塊沒有異常時,else分支觸發執行;當迴圈沒有被break終止時,else分支觸發執行。想要學習更多try語句塊和異常,參見Handling Exceptions

continue語句,是從C語言借鑑的,直接執行迴圈的下一次。

  >>> for num in range(2, 10):
  ...     if num % 2 == 0:
  ...         print("Found an even number", num)
  ...         continue
  ...     print("Found a number", num)
  Found an even number 2
  Found a number 3
  Found an even number 4
  Found a number 5
  Found an even number 6
  Found a number 7
  Found an even number 8
  Found a number 9

4.5. pass語句

pass語句什麼也不執行。它可以背用於語法需要,但程式並不想執行任何任務。例如:

  >>> while True:
  ...     pass  # Busy-wait for keyboard interrupt (Ctrl+C)
  ...

它通常被用於建立一個最小的類:

  >>> class MyEmptyClass:
  ...     pass
  ...

另一個用處是,當你正在寫新的程式碼,可以將pass寫在函式體或者條件子句體中,用以標記佔位,這使你在更抽象層面思考。pass會被自動忽略。

  >>> def initlog(*args):  
  ...     pass   # Remember to implement this!  
  ...  

4.6 函式定義

我們可以寫一個可以輸出不超過指定邊界值的斐波那契數列的函式:

  >>> def fib(n):    # write Fibonacci series up to n
  ...     """Print a Fibonacci series up to n."""
  ...     a, b = 0, 1
  ...     while a < n:
  ...         print(a, end=' ')
  ...         a, b = b, a+b
  ...     print()
  ...
  >>> '# Now call the function we just defined:
  ... fib(2000)
  0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

關鍵詞def定義了一個函式。它後邊是函式名字和被括號包括起來的一串引數。函式體的宣告是從下一行開始的,而且必須縮排。

函式體的第一行可以是一個隨意的字串陣列;字串陣列是函式的文件字串或者docstring。(更多關於docstring的說明可以在文件API部分找到)。有一些工具可以使用docstrings製作線上文件或者列印文件,或者讓使用者互動式的瀏覽程式碼;在程式碼中寫入docstrings是一個很好的做法,你應該養成習慣。

函式執行時會為區域性變數引入一個新的符號表。所有的區域性變數都儲存在這個區域性符號表中。引用引數時,會先從區域性符號表中查詢,然後是全域性符號表,然後是內建命名錶。因此,全域性引數雖然可以被引用,但它們不能在函式中直接賦值(除非它們在全域性宣告語句中)。

函式引用的實際引數在函式呼叫時引入區域性符號表,因此,實參總是傳值呼叫(這裡的值指的是物件引用,而不是該物件的值)。[1] 一個函式被另一個函式呼叫時,一個新的區域性符號表在呼叫過程中被建立。

函式的定義過程會在函式當前引數列表前定義函式名字。作為使用者定義函式,函式名有一個為直譯器認可的型別值。這個值可以賦給其它命名,使其能夠作為一個函式來使用。這就像一個重新命名機制:

  >>>
  >>> fib
  <function fib at 10042ed0>
  >>> f = fib
  >>> f(100)
  0 1 1 2 3 5 8 13 21 34 55 89

類比其它程式語言,你可能認為fib不是一個函式( function ),而是一個過程( procedure )。Python 和 C 一樣,過程只是一個沒有返回值的函式。實際上,沒有顯式宣告返回值的過程也有一個返回值,雖然是一個不討人喜歡的值。這個值被稱為 None (這是一個內建命名)。如果一個值只是 None 的話,通常直譯器不會寫一個 None 出來,如果你真想要檢視它的話,可以這樣做:

  >>>

  >>> fib(0)
  >>> print(fib(0))
  None

我們來寫一個簡單的示例,用於演示如何從函式中返回一個包含菲波那契數列的數值連結串列,而不是列印它: 、

  >>>
  >>> def fib2(n):  # return Fibonacci series up to n
  ...     """Return a list containing the Fibonacci series up to n."""
  ...     result = []
  ...     a, b = 0, 1
  ...     while a < n:
  ...         result.append(a)    # see below
  ...         a, b = b, a+b
  ...     return result
  ...
  >>> f100 = fib2(100)    # call it
  >>> f100                # write the result
  [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

和以往一樣,上面的例子演示了一些新的 Python 功能:

  • return 語句從函式中返回一個值,不帶表示式的 return 返回 None。過程結束後也會返回 None 。
  • 語句result.append(b)稱為連結串列物件 result 的一個函式。函式是一個“屬於”某個物件的,它被命名為 obj.methodename,這裡的 obj 是某個物件(可能是一個表示式),methodename是某個在該物件型別定義中的方法的命名。不同的入參型別定義不同的方法。不同入參型別也有可能名字相同,但不會混淆。(當你定義自己的物件型別和方法時,可能會出現這種情況,本指南後面的章節會介紹如何使用型別)。示例中演示的 append()方法由連結串列物件定義,它向連結串列中加入一個新元素。在示例中它等同於””result = result + [b]””,不過效率更高。