python之函数递归与调用

本文深入探讨了Python中的函数递归与调用,包括递归的基本概念、直接和间接调用示例、递归最大深度的设置与查看、递归的本质以及递归的两个阶段。通过实例解析了递归调用的终止条件和问题规模的减少,强调了递归调用的正确使用方法。最后,展示了递归在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

python之函数递归与调用

一、什么是函数递归调用?

  • 递归调用是函数嵌套调用的一种特殊形式
  • 函数在调用时, 直接或间接调用了本身, 这就是递归调用
  • 递归的本质就是循环

二、直接和间接调用示例

  • 直接调用:死循环,无意义
def f1():
    print('from f1')
    f1()
f1()    # 当超过递归最大深度时报错 "RecursionError"
  • 间接调用
def bar():
    print('sa')
    foo()

def foo():
    print('sds')
    bar()

foo()   # 这样来回调用无意义, 当超过递归最大深度时报错 "RecursionError"

三、递归最大深度设置与查看

死循环与递归的差别:

死循环并不会产生新的内存空间, 而函数的递归要不断的申请内存空间. 所以函数的递归要设置最大递归深度.

递归最大深度设置与查看
  • 调用函数会产生局部的名称空间,占用内存,因为上述这种调用会无休止调用本身
  • 为了防止其无限制占用内存,python 解释器的内存管理机制对函数的递归调用做了最大的层级限制

ps : 虽然可以修改, 但应该有边界, 不可能无限制的递归, 那样无意义, 递归应分为明确的两个阶段 (回溯, 递推)

示例:

# 查看递归深度: 默认值1000
import sys
print(sys.getrecursionlimit())  # 1000

# 指定递归深度: 但最终会受限于主即操作系统大小的限制
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())  # 2000

四、递归的本质

# 方式一: while, for循环
while True:
    print(111)
    print(222)
    print(333)
    
    
# 方式二: 递归的本质就是循环
def func():
    print(111)
    print(222)
    print(333)
    func()
func()  

五、强调:递归调用必须在满足某种条件下结束,不能无限递归调用下去

# while循环示例
i = 0
# 1. while循环
while i < 10:  # 2. 循环结束条件
    print(i, end=' ')  # 0 1 2 3 4 5 6 7 8 9
    i += 1  # 3. 累加条件
    
# 递归本质就是循环示例
def func(i):
    if i == 10:  # 2. 指定同while循环一样的结束循环的条件
        return
    print(i, end=' ')  # 0 1 2 3 4 5 6 7 8 9
    i += 1  # 3. 指定同while循环一样的累加条件

    func(i)  # 1. 同while循环一样让函数循环起来

func(0)

六、递归的两个阶段

  • 回溯
    • 回溯就是从外向里层一层一层递归调用下去
    • 回溯阶段必须要有一个明确的结束条件
    • 每次进入下一次递归时, 问题的规模应该减少,否则单纯的无限的递归毫无意义
  • 递推
    • 当某一层满足某种结束条件,结束了递归调用,然后从里到外一层一层返回结束递归调用

示例

# "回溯阶段"
age(5)=age(4)+2
age(4)=age(3)+2
age(3)=age(2)+2
age(2)=age(1)+2
age(1)=18  # 求 age(5) 的值

# 先研究表达式如何成立
n > 1 : age(n) = age(n-1) + 2
n = 1 : age(n) = 18

# 写函数计算 : "递推阶段"
def age(n):
    if n == 1:
        return 18
    return age(n-1)+2  # age(4)+2 = age(3)+2+2 = age(2)+2+2+2 = age(1)+2+2+2+2 = 18+8 = 26
print(age(5))          # 26

案例:

# 示例一: 有5个人, 第5个人说我的薪资比第4个人多1000, 第4个人说我的薪资比第3个人多1000, 第3个人说我的薪资比第2个人多1000, 第1个人说我的薪资是5000, 求第5个人的薪资?
def salary(n):
    if n == 1:  # 结束条件
        return 5000    
    return salary(n - 1) + 1000  # salary(4) + 1000 + salary(3) + 1000 + salary(2) + 1000 + salary(1) + 1000

s = salary(5)
print(s)  # 9000

# 示例二: 有5个人, 第5个人说我的年龄比第4个人大2岁, 第4个人说我的年龄比第3个人大2岁,第3个人说我的年龄比第2个人大2岁,第2个人说我的年龄比第1个人大2岁, 第1个人说我的年龄是38, 求第5个人年龄?
def age(n):
    if n == 1:  # 结束条件
        return 38
    return age(n-1) + 2  # 循环条件age(n-1) + 累加条件2  

print(age(5))  # 46

# 应用场景: 需求, 取出列中的每一个值
items = [1, 2, [3, [4, [5, [6, [7, [8, [9, 10, 11, [12, [13, ]]]]]]]]]]
def func(li: list):
    for item in li:  # 结束条件: li被迭代取值完毕
        if isinstance(item, list):
            func(item)  # 循环条件: 如果item不是列表, 那么继续递归
        else:
            print(item, end=' ')

func(items)  # 1 2 3 4 5 6 7 8 9 10 11 12 13 

七、总结

  • 递归调用一定要有一个明确的结束条件(必须在满足某种条件下结束)
  • 每次进入下一次递归,问题的规模都应该减少
  • 在python中没有尾递归优化
问题规模减少简单示例:
# 将不是列表的值打印出来
l = [1, [2, [3, [4, [5, [6, [7, [8, [9]]]]]]]]]

def outter(itmes):
    for line in itmes:
        if type(line) is not list:
            print(line)
        else:
            outter(line)

outter(l)  # 1,2,3,4,5,6,7,8,9
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾维斯Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值