跳轉到內容

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

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

有些人發現這一部分很有用,有些人則覺得它令人困惑。如果你覺得它令人困惑,你可以跳過它(或者只看看示例)。現在我們將對以下程式進行逐步講解

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 * 2 =  6

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


執行 1

問題:程式首先執行什麼?
回答:首先執行的是定義函式 mult,包括除最後一行之外的所有行。
定義函式 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 函式進行逐步講解才能找出答案。

執行 2

接下來會發生什麼?
變數 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 函式。
執行 2
def mult(3, 2):
    if b == 0:
        return 0
    rest = mult(3, 2 - 1)
    value = 3 + rest
    return value



執行 3

那麼接下來會發生什麼?
函式的執行中的區域性變數被設定,以便 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) 行。現在返回值可以被賦予變數 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

如果你仍然對這個例子有疑問,可以反向檢視這個過程。最後一步是什麼?我們可以很容易地看出 mult(3, 0) 的結果是 0。由於 b0,因此函式 mult(3, 0) 將返回 0 並停止。

那麼前一步做了什麼?mult(3, 1) 不會返回 0,因為 b 不是 0。所以執行接下來的幾行:rest = mult (a, b - 1),即 rest = mult (3, 0),即 0,正如我們剛才計算出來的那樣。所以現在變數 rest 被設為 0

下一行將 rest 的值加到 a 上,由於 a3rest0,因此結果是 3

現在我們知道函式 mult(3, 1) 返回 3。但我們想知道 mult(3,2) 的結果。因此,我們需要回到程式的開頭,再執行一次:mult(3, 2)rest 設為 mult(3, 1) 的結果。我們從上一輪知道這個結果是 3。然後 value 計算為 a + rest,即 3 + 3。然後,3 * 2 的結果被列印為 6。

這個例子要說明的是,函式 mult(a, b) 在自身內部啟動自身。它會一直這樣做,直到 b 達到 0,然後根據上面解釋的方式計算出結果。

這種程式設計結構被稱為遞迴,可能是對遞迴最直觀的定義是


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

最後兩部分是最近撰寫的。如果你有任何意見,發現任何錯誤,或者認為我需要更多/更清晰的解釋,請傳送電子郵件。我過去曾以簡單易懂的方式使事情變得難以理解。如果教程的其餘部分都講得通,但這一部分講不通,那很有可能是我的錯,我想知道。謝謝。

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

Commented_mult.py

# The comments below have been numbered as steps, to make explanation
# of the code easier. Please read according to those steps.
# (step number 1, for example, is at the bottom)


def mult(a, b): # (2.) This function will keep repeating itself, because....
    if b == 0:
        return 0
    rest = mult(a, b - 1) # (3.) ....Once it reaches THIS, the sequence starts over again and goes back to the top!
    value = a + rest
    return value # (4.) therefore, "return value" will not happen until the program gets past step 3 above

print "3 * 2 = ", mult(3, 2) # (1.) The "mult" function will first initiate here
                             

# The "return value" event at the end can therefore only happen
# once b equals zero (b decreases by 1 everytime step 3 happens).
# And only then can the print command at the bottom be displayed.

# See it as kind of a "jump-around" effect. Basically, all you
# should really understand is that the function is reinitiated
# WITHIN ITSELF at step 3. Therefore, the sequence "jumps" back
# to the top.

Commented_factorial.py

# Another "jump-around" function example:

def factorial(n): # (2.) So once again, this function will REPEAT itself....
    if n <= 1:
        return 1
    return n * factorial(n - 1) # (3.) Because it RE-initiates HERE, and goes back to the top.

print "2! =", factorial(2) # (1.) The "factorial" function is initiated with this line
print "3! =", factorial(3)
print "4! =", factorial(4)
print "5! =", factorial(5)

Commented_countdown.py

# Another "jump-around", nice and easy:


def count_down(n): # (2.) Once again, this sequence will repeat itself....
    print n
    if n > 0:
        return count_down(n-1) # (3.) Because it restarts here, and goes back to the top

count_down(5) # (1.) The "count_down" function initiates here


華夏公益教科書