跳轉到內容

Python 3 非程式設計師教程/高階函式示例

來自華夏公益教科書,開放世界開放書籍

注意:有些人發現這一節很有用,有些人則覺得它很混亂。如果你覺得它很混亂,可以跳過它,繼續下一節。

為了展示更高階的函式使用方式,我們現在將對以下程式進行逐步講解

def mult(a, b):
    if b == 0:
        return 0
    rest = mult(a, b - 1)
    value = a + rest
    return value
result = mult(3, 2)
print("3 * 2 = ", result)

基本上,這個程式建立了一個正整數乘法函式(比內建乘法函式慢得多),然後用一個函式的使用來演示這個函式。這個程式演示了遞迴的使用,遞迴是迭代(重複)的一種形式,其中有一個函式重複呼叫自身,直到滿足退出條件。它使用重複加法來獲得與乘法相同的結果:例如,3 + 3(加法)與 3 * 2(乘法)的結果相同。

問題:程式首先做什麼?
答案:首先是使用以下幾行定義了函式 mult
def mult(a, b):
    if b == 0:
        return 0
    rest = mult(a, b - 1)
    value = a + rest
    return value
這將建立一個函式,該函式接受兩個引數,並在完成時返回一個值。稍後可以執行此函式。
接下來會發生什麼?
函式後面的那行,result = mult(3, 2) 會被執行。
這一行做了什麼?
這一行將把 mult(3, 2) 的返回值賦給變數 result
那麼 mult(3, 2) 返回什麼呢?
我們需要對 mult 函式進行逐步講解才能找出答案。
接下來會發生什麼?
變數 a 被分配了值 3,變數 b 被分配了值 2。
然後呢?
執行 if b == 0: 這行。由於 b 的值為 2,所以這行是假的,因此跳過 return 0 這行。
然後呢?
執行 rest = mult(a, b - 1) 這行。這一行將區域性變數 rest 設定為 mult(a, b - 1) 的值。 a 的值為 3, b 的值為 2,所以函式呼叫是 mult(3,1)
那麼 mult(3, 1) 的值是多少呢?
我們需要使用引數 3 和 1 來執行 mult 函式。
所以接下來會發生什麼?
函式執行中,區域性變數被設定為 a 的值為 3, b 的值為 1。由於這些是區域性值,所以它們不會影響 ab 的先前值。
然後呢?
由於 b 的值為 1,所以 if 語句為假,所以下一行變為 rest = mult(a, b - 1)
這一行做了什麼?
這一行將 mult(3, 0) 的值分配給 rest。
那麼那個值是什麼呢?
我們必須再執行一次函式才能找出答案。這次 a 的值為 3,b 的值為 0。
所以接下來會發生什麼?
函式中要執行的第一行是 if b == 0: b 的值為 0,所以要執行的下一行是 return 0
return 0 這行做了什麼?
這一行將值 0 返回函式。
所以呢?
所以現在我們知道 mult(3, 0) 的值為 0。現在我們知道 rest = mult(a, b - 1) 這一行做了什麼,因為我們已經使用引數 3 和 0 運行了 mult 函式。我們已經完成了 mult(3, 0) 的執行,現在回到了執行 mult(3, 1)。變數 rest 被分配了值 0。
接下來執行哪一行?
接下來執行 value = a + rest 這一行。在此函式執行中,a = 3rest = 0,所以現在 value = 3
接下來會發生什麼?
執行 return value 這一行。這將從函式中返回 3。這還將退出 mult(3, 1) 函式的執行。在呼叫 return 之後,我們返回執行 mult(3, 2)
我們在 mult(3, 2) 中在哪裡?
我們有變數 a = 3b = 2,並且正在檢查 rest = mult(a, b - 1) 這一行。
所以現在會發生什麼?
變數 rest 被分配了 3。下一行 value = a + restvalue 設定為 3 + 3 或 6。
所以現在會發生什麼?
執行下一行,這將從函式中返回 6。我們現在回到了執行 result = mult(3, 2) 這一行,現在可以將值 6 分配給變數 result
接下來會發生什麼?
函式後面的那行,print("3 * 2 = ", result) 會被執行。
這做了什麼?
它列印 3 * 2 = result 的值,即 6。列印的完整行是 3 * 2 = 6
總的來說發生了什麼?
基本上我們使用兩個事實來計算這兩個數字的倍數。第一個是任何數字乘以 0 等於 0(x * 0 = 0)。第二個是,一個數字乘以另一個數字等於第一個數字加上第一個數字乘以第二個數字減 1(x * y = x + x * (y - 1))。所以發生的是,3 * 2 首先被轉換為 3 + 3 * 1。然後 3 * 1 被轉換為 3 + 3 * 0。然後我們知道任何數字乘以 0 等於 0,所以 3 * 0 等於 0。然後我們可以計算出 3 + 3 * 0 等於 3 + 0,即 3。現在我們知道 3 * 1 等於多少,所以我們可以計算出 3 + 3 * 1 等於 3 + 3,即 6

這就是整個過程的工作原理

mult(3, 2)
3 + mult(3, 1)
3 + 3 + mult(3, 0)
3 + 3 + 0
3 + 3
6

透過解決問題的較小版本來解決問題的程式設計結構稱為遞迴。在本節的示例中,遞迴是透過定義一個函式來實現的,該函式呼叫自身。這有利於實現程式設計任務的解決方案,因為它可能只需要考慮問題的下一步,而不是同時考慮整個問題。它也很有用,因為它允許用簡潔易懂的程式碼來表達一些數學概念。

任何可以用遞迴解決的問題都可以用迴圈重新實現。使用後者通常會帶來更好的效能。然而,使用迴圈的等效實現通常更難正確完成。

遞迴 的最直觀的定義可能是

遞迴
如果你仍然不明白,請參閱遞迴

如果乘法示例沒有講清楚,請嘗試逐步講解階乘示例。

factorial.py

#defines a function that calculates the factorial

def factorial(n):
    if n == 0:
        return 1
    if n<0:
        return "Error, negative numbers do not have factorial values!!"
    return n * factorial(n - 1)

print("2! =", factorial(2))
print("3! =", factorial(3))
print("4! =", factorial(4))
print("5! =", factorial(5))
print("-3! =", factorial(-3))

輸出

2! = 2
3! = 6
4! = 24
5! = 120
-3! = Error, negative values do not have factorial values!!

countdown.py

def count_down(n):
    print(n)
    if n > 0:
        return count_down(n-1)

count_down(5)

輸出

5
4
3
2
1
0


Python 3 非程式設計師教程
 ← 定義函式 高階函式示例 列表 → 
華夏公益教科書