跳轉到內容

使用 Linkbot 學習 Python 3 / 高階函式示例

來自華夏公益教科書

有些人覺得這一部分很有用,有些人覺得它很混亂。如果你覺得它很混亂,你可以跳過它。現在我們將對以下程式進行逐步講解

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

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

問題:程式的第一件事是什麼?
答案:首先是使用以下程式碼行定義函式 mult
def mult(a, b):
    if b == 0:
        return 0
    rest = mult(a, b - 1)
    value = a + rest
    return value
這建立了一個函式,該函式接受兩個引數,並在完成後返回一個值。稍後可以執行此函式。
接下來會發生什麼?
函式之後的下一行,print("3 * 2 = ", mult(3, 2)) 執行。
它做了什麼?
它打印出3 * 2 = mult(3, 2) 的返回值。
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。現在我們回到了執行 print("3 * 2 = ", mult(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

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

3 * 2
3 + 3 * 1
3 + 3 + 3 * 0
3 + 3 + 0
3 + 3
6

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

任何可以使用遞迴解決的問題都可以使用迴圈重新實現。使用迴圈通常會導致更好的效能。但是,使用迴圈的等效實現通常更難正確完成。

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

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

如果你覺得乘法示例沒有意義,請嘗試逐步講解階乘示例。

factorial.py

#defines a function that calculates the factorial

def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

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

輸出

2! = 2
3! = 6
4! = 24
5! = 120

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


使用 Linkbot 學習 Python 3
 ← 定義函式 高階函式示例 列表 → 
華夏公益教科書