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,包括除最后一行之外的所有行。
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
函数。
def mult(3, 2):
if b == 0:
return 0
rest = mult(3, 2 - 1)
value = 3 + rest
return value
运行 3
- 那么接下来会发生什么?
- 函数的新运行中的局部变量被设置,以便
a
的值为 3,b
的值为 1。由于这些是局部值,因此它们不会影响a
和b
的先前值。
- 然后呢?
- 由于
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 = 3
,rest = 0
,因此现在value = 3
。
- 接下来会发生什么?
- 执行
return value
行。这将从函数中返回 3。这也将退出mult(3, 1)
的运行。在调用return
之后,我们将返回运行mult(3, 2)
。
- 我们在
mult(3, 2)
中哪里? - 我们有变量
a = 3
和b = 2
,并且正在检查rest = mult(a, b - 1)
行。
- 那么现在会发生什么?
- 变量
rest
被赋予值 3。下一行value = a + rest
将value
设为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
。由于 b
是 0
,因此函数 mult(3, 0)
将返回 0
并停止。
那么前一步做了什么?mult(3, 1)
不会返回 0
,因为 b
不是 0
。所以执行接下来的几行:rest = mult (a, b - 1)
,即 rest = mult (3, 0)
,即 0
,正如我们刚才计算出来的那样。所以现在变量 rest
被设为 0
。
下一行将 rest
的值加到 a
上,由于 a
是 3
,rest
是 0
,因此结果是 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