前言
学习一门语言最好的办法,就是教懂别人。在这公众号,我会从 Python 最基础的教程写起,慢慢一步步进阶。Python 基础比较好的欢迎去精选文章里看看爬虫实战项目,欢迎指教。
今天和大家一起学习下 Python 中的一种特殊函数:递归函数。递归函数的优点是定义简单,逻辑清晰。
大家应该知道,数学中阶乘的概念,n!=1×2×3×…×n。先给大家出个题目,用 Python 的 for 循环计算出 5 的阶乘。这个应该不难,略懂基础的应该有答案了。
Python
mul = 1
for i in range(1, 6):
mul = mul*i
print(mul)
# 结果:
120
1
2
3
4
5
6
7
mul=1
foriinrange(1,6):
mul=mul*i
print(mul)
# 结果:
120
这种方法比较简单,那有没有 pythonic 点的方法呢?随时都可以调用,输入不同的数从而得到不同值。有的,这个就是我们今天要讲到的递归函数。
递归函数
递归函数怎么表示阶乘呢?
Python
def fun(n):
if n == 1:
return 1
else:
return n*fun(n-1)
print(fun(5))
# 结果:
120
1
2
3
4
5
6
7
8
9
10
deffun(n):
ifn==1:
return1
else:
returnn*fun(n-1)
print(fun(5))
# 结果:
120
我们看到,结果是一样的,什么是递归函数呢?一个函数在内部调用自身本身,这个函数就是递归函数。
原理分析
上面的例子很好理解,再看一个复杂点的例子:
Python
def recurion(num):
print(num)
if num > 0:
recurion(num - 1)
else:
print('------')
print(num)
recurion(3)
1
2
3
4
5
6
7
8
9
defrecurion(num):
print(num)
ifnum>0:
recurion(num-1)
else:
print('------')
print(num)
recurion(3)
这个结果是多少呢?是不是下面这个答案呢?
Python
3
2
1
0
------
0
1
2
3
4
5
6
3
2
1
0
------
0
我第一次理解递归函数时也是给出这个答案。实际上的答案是下面这样的:
Python
3
2
1
0
------
0
1
2
3
1
2
3
4
5
6
7
8
9
3
2
1
0
------
0
1
2
3
what?这是为啥,关键点在退出判断语句的 print() 语句。我们知道人都会健忘,做第一件事被别人打断去做了第二件事,第二件事做了一部分又被打断,又去做了第三件事,做完第三件事之后,可能当天就忘了还有第一件事和第二件事没有完成。但是计算机不会忘,之前没执行的还会继续执行。我用详细的分解步骤给大家分解下 recurion(3) 的实现步骤。
Python
def recurion(3):
print(3)
if 3 > 0:
recurion(2) # 调用自身函数
print(2)
if 2 > 0:
recurion(1) # 调用自身函数
print(1)
if 1 > 0:
recurion(0) # 调用自身函数
print(0)
if 0 > 0:
不成立,执行else
else:
print('------')
print(0)
print(1) # 执行未完成的任务
print(2) # 执行未完成的任务
print(3) # 执行未完成的任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
defrecurion(3):
print(3)
if3>0:
recurion(2)# 调用自身函数
print(2)
if2>0:
recurion(1)# 调用自身函数
print(1)
if1>0:
recurion(0)# 调用自身函数
print(0)
if0>0:
不成立,执行else
else:
print('------')
print(0)
print(1)# 执行未完成的任务
print(2)# 执行未完成的任务
print(3)# 执行未完成的任务
在调用函数本身时,它之后的代码并没有结束,而是在等待条件为 False 时,再接着执行之后的代码。所以之前调用自身函数 3、2、1 时,条件为 False 时,计算机还是会记得去执行它,按照先进后出的顺序。
递归函数优点
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
递归函数缺点
递归调用的次数过多,会导致栈溢出。还是用之前阶乘的例子,1000 的阶乘用递归函数会报错。
Python
def fun(n):
if n == 1:
return 1
else:
return n*fun(n-1)
print(fun(1000))
# 结果:
RecursionError: maximum recursion depth exceeded in comparison
1
2
3
4
5
6
7
8
9
10
11
deffun(n):
ifn==1:
return1
else:
returnn*fun(n-1)
print(fun(1000))
# 结果:
RecursionError:maximumrecursiondepthexceededincomparison
我们看到,当递归数值比较大时,报错了,由于递归调用次数过多,堆栈溢出。Python 解释器没有对此做优化。所以遇到这种情况,我们需要放弃递归,使用 for 循环来解决。
在最后
感谢你能看到这里,希望我写的东西能够让你有到收获,但是我还是希望我在文章里插入的代码,你们能自己动手试一下,都很简单。原创不易,每一个字,每一个标点都是自己手敲的,所以希望大家能多给点支持。