1、递归的定义
在一个函数里再调用这个函数本身,这种使用函数的方式就叫做递归。
一个最简单的递归函数。
1 def story(): 2 s = """ 3 从前有个山,山里有座庙,庙里老和尚讲故事, 4 讲的什么呢? 5 """ 6 print(s) 7 story() 8 9 story()
下面这种形式也是递归函数:
1 def bar(): 2 print('from bar') 3 func() 4 5 def func(): 6 print('from bar') 7 bar()
2、递归的最大深度——997
正如你们刚刚看到的,递归函数如果不受到外力的阻止会一直执行下去。但是我们之前已经说过关于函数调用的问题,每一次函数调用都会产生一个属于它自己的名称空间,如果一直调用下去,就会造成名称空间占用太多内存的问题,于是python为了杜绝此类现象,强制的将递归层数控制在了997。
拿什么来证明这个“997理论”呢?这里我们可以做一个实验:

1 def foo(n): 2 print(n) 3 n += 1 4 foo(n) 5 foo(1)

1 import sys 2 print(sys.getrecursionlimit())#默认层级 3 #>>>1000
由此我们可以看出,未报错之前能看到的最大数字就是997。当然了,997是python为了我们程序的内存优化所设定的一个默认值,我们当然还可以通过一些手段去修改它:

1 import sys 2 print(sys.setrecursionlimit(100000))
我们可以通过这种方式来修改递归的最大深度,刚刚我们将python允许的递归深度设置为了10w,至于实际可以达到的深度就取决于计算机的性能了。不过我们还是不推荐修改这个默认的递归深度,因为如果用997层递归都没有解决的问题要么是不适合使用递归来解决要么是你代码写的太烂了。
备注:不算第一次递归997,算第一次递归是998
3、示例
1 #1、第一个人比第二个人小两岁,第二个人比第三个人小两岁,以此类推,第一个18岁,计算第五个人的年龄 2 def age(n): 3 if n==1: 4 return 18 5 return age(n-1)+2 6 7 res=age(5) 8 print(res) 9 10 #2、打印列表中每个元素的值 11 l=[1,[2,[3,[4,[5]]]]] 12 def func(l): 13 for item in l: 14 if type(item) is list: 15 func(item) 16 else: 17 print(item) 18 19 func(l)
4、总结
递归分为两个阶段:递推,回溯
python中的递归python中的递归效率低,需要在进入下一次递归时保留当前的状态,在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,尾递归优化。但是python又没有尾递归,且对递归层级做了限制
总结递归的使用:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
5、练习题
1 #递归函数练习题 2 #阶乘 3 def fac(n): 4 if n == 1: 5 return 1 6 return n * fac(n-1) 7 8 print(fac(10))#>>>3628800 9 10 #斐波那契 计算第n斐波那契是多少 11 #1,1,2,3,5,8 12 #第一种方法 13 def fib(n): 14 if n == 1 or n == 2: 15 return 1 16 return fib(n-1) + fib(n-2) 17 print(fib(5))#>>>5 18 19 #第二种方法 20 def fib(n,l=[0]): 21 l[0] +=1 22 if n == 1 or n == 2: 23 l[0] -= 1 24 return 1,1 25 else: 26 a,b = fib(n-1) 27 l[0] -= 1 28 if l[0] == 0: 29 return a+b 30 return b,a+b 31 32 print(fib(50))#>>>12586269025
6、三级菜单

menu = { '北京': { '海淀': { '五道口': { 'soho': {}, '网易': {}, 'google': {} }, '中关村': { '爱奇艺': {}, '汽车之家': {}, 'youku': {}, }, '上地': { '百度': {}, }, }, '昌平': { '沙河': { '老男孩': {}, '北航': {}, }, '天通苑': {}, '回龙观': {}, }, '朝阳': {}, '东城': {}, }, '上海': { '闵行': { "人民广场": { '炸鸡店': {} } }, '闸北': { '火车战': { '携程': {} } }, '浦东': {}, }, '山东': {}, }

def threeLM(dic): while True: for k in dic:print(k) key = input('input>>').strip() if key == 'b' or key == 'q':return key elif key in dic.keys() and dic[key]: ret = threeLM(dic[key]) if ret == 'q': return 'q' threeLM(menu)

l = [menu] while l: for key in l[-1]: print(key) inp = input('>>>') if inp in l[-1]: l.append(l[-1][inp]) elif inp == 'b': l.pop() elif inp == 'q': break