递归遇到的一些坑。
为什么递归函数会返回None
def calc(n,count):
'''
:param n: 需要进行递归的对象
:param count: 计数器
:return: 条件不成立时,返回最终值
'''
# print(n,count)
if count < 5: #运行第五次时退出
calc(n//2,count+1) #每一层接收它下一层的值,return必不可少,否则倒数第三层无法接收倒数第二层的返回值
else:
return n # 在上一个return 递归函数被中止
f = calc(199,1)
print('res运算第五次时的结果:',f) # 输出>>res运算第五次时的结果: 12
def t(n):
if n ==1:
return n
return t(n-1) # 递归函数在 n=2在时候调用结束,这里不加return就会返回为None
print(t(4))
上面的例子:在调用递归处不加return 就会返回None.因为在递归结束处并没有返回值,所以默认返回None。当多加一个return是把下层的return返回回来,一层层返回,最后返回值才会是n
再看一个求列表叠加的例子
a = [1,5,7,9]
def sum(a):
if isinstance(a, list) and len(a) >1:
# return a[0] +sum(a[1:])
a[0] +sum(a[1:])
else:
return a[0]
如果注释处不加return 就会报错。因为递归处返回的是None None和int不能相加
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
1。 递归函数在for循环里面return,会结束for循环,所以不能在for循环里面return 递归函数 8行代码处。for循环自带递归 return
a = [1,3,4,["啊登","向佳","咸维维",[66,77]],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
from collections.abc import Iterable
# 1。 递归函数在for循环里面return,会结束for循环,所以不能在for循环里面return 递归函数 8行代码处。for循环自带递归 return
def get_a(a):
b = []
for i in a:
if isinstance(i, Iterable) and (not isinstance(i, (str, bytes))):
return get_a(i)
else:
b.append(i)
return b
print(get_a(a)) [66, 77]
可以发现 在for循环里面return 递归函数 最后得到的结果只有一组,以为 for循环遇到return终止了当前循环,比如a列表 [[15,19,["香蕉",["西瓜","芒果"]]]元素并没有循环到。那么怎么办呢? for 不加return呢?
a = [1,3,4,["啊登","向佳","咸维维",[66,77]],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
def get_a(a):
b = []
for i in a:
if isinstance(i, Iterable) and (not isinstance(i, (str, bytes))):
get_a(i)
else:
b.append(i)
return b
print(get_a(a)) [1, 3, 4]
当调用get_a(i) 递归调用的时候,每一个列表for循环结束后会返回当前调用的返回值b,可以看出a对象里面有多个列表,那么递归调用就会返回多个返回值b. 这个每一次的返回值 并没有做整合处理。所以上面最后的返回值是 [1,3,4]
当递归遍历想要所有的结果的时候,不能在for循环里面return 递归函数。 for循环结束后return 可以接受递归一次的返回值。如果递归的每一次结果都要叠加到一起可以这么做:
- 如果返回值可以叠加操作,可以用 res += 递归调用。
- 如果递归返回值是列表,可以 列表.extend(递归调用)
- 还有一种的就从外表传参给个空列表传给函数,函数用一个变量去接收这个空别表。 在递归调用处直接这样调用。fo(x,当前列表) x是参数, 当前列表第一次值是传过来的空列表。
案例1
import os
def count_dir_size(path):
""""统计文件或者文件夹大小,返回的是字节"""
count_size = 0
if not os.path.isdir(path):
return os.path.getsize(path)
else:
for f in os.listdir(path):
new_path = os.path.join(path, f)
if os.path.isfile(new_path):
count_size = count_size + os.path.getsize(new_path)
else:
count_size = count_size + count_dir_size(new_path)
return count_size
案例2
取出列表a所有的元素,放在一个新列表里面
a = [1,3,4,["啊登","向佳","咸维维",[66,77]],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
def get_a(a):
b = []
for i in a:
if isinstance(i, Iterable) and (not isinstance(i, (str, bytes))):
b.extend(get_a(i))
else:
b.append(i)
return b
print(get_a(a))
[1, 3, 4, '啊登', '向佳', '咸维维', 66, 77, 15, 19, '香蕉', '西瓜', '芒果', 8, 0]
案例3
如果递归调用,对调用处不做任何处理,可以外部穿一个参数,比如空列表
a = [1,3,4,["啊登","向佳","咸维维",[66,77]],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
def get_a(a,list_none):
b = list_none
for i in a:
if isinstance(i, Iterable) and (not isinstance(i, (str, bytes))):
get_a(i, b)
else:
b.append(i)
return b
print(get_a(a, []))
案例4
yield from 函数。去做处理
a = [1,3,4,["啊登","向佳","咸维维",[66,77]],[[15,19,["香蕉",["西瓜","芒果"]]],8,0]]
def get_a(a):
for i in a:
if isinstance(i, Iterable) and (not isinstance(i, (str, bytes))):
yield from get_a(i)
else:
yield i
print(list(get_a(a)))
网友评论