Python学习总结(9)python中函数的递归 和 pycharm社区版中空格、table的显示

本文介绍了Python递归函数的基本概念、递归使用示例及如何防止栈溢出,强调了尾递归优化在防止栈溢出中的作用。同时,详细说明了如何在PyCharm社区版中设置显示空格和制表符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
先记住: 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

1.递归函数知识点

使用递归函数应该知悉:

  1. 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数
  2. 归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式, 但循环的逻辑不如递归清晰。
  3. 使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

2. 递归函数使用举例子

  1. 举个例子,我们来计算阶乘n! = 1 x 2 x 3 x … x n,用函数fact(n)表示,可以看出:

    fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n-1) x n

    所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。

    于是,fact(n)用递归的方式写出来就是:

    def fact(n):
        if n==1:
            return 1
        return n * fact(n - 1) #注意留意此处。retuen的返回值是在返回值里面调用递归函数
    

    输入调用进行检验

    >>> fact(1)
    1
    >>> fact(5)
    120
    

    如果我们计算fact(5),可以根据函数定义看到计算过程如下:

    		===> fact(5)
    		===> 5 * fact(4)
    		===> 5 * (4 * fact(3))
    		===> 5 * (4 * (3 * fact(2)))
    		===> 5 * (4 * (3 * (2 * fact(1))))
    		===> 5 * (4 * (3 * (2 * 1)))
    		===> 5 * (4 * (3 * 2))
    		===> 5 * (4 * 6)
    		===> 5 * 24
    		===> 120
    

2.但是由于该种递归方式是栈的方式,当数据过大会造成栈的溢出,如下:

		>> fact(9999)
		Traceback (most recent call last):
		  File "<stdin>", line 1, in <module>
		  File "<stdin>", line 4, in fact
		  ...
		  File "<stdin>", line 4, in fact
		RuntimeError: maximum recursion depth exceeded in comparison

解决方式请看第3点。

3. 常用递归函数的优化,尾部递归 理解为函数在进行递归前先算好每一次传入的结果

  • 解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的

  • 尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。 这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

释惑:上面的fact(n)函数由于return n * fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:
(1)

	def fact(n):
	    return fact_iter(n, 1) 
	
	def fact_iter(num, product):
	    if num == 1:
	        return product
	    return fact_iter(num - 1, num * product) #注意此处与(2)对比
	    #在返回之前,进行了 fact_iter(num - 1, num * product) 参数内部的计算,没有使用数与递归相乘

(2)

	def fact(n):
	    if n==1:
	        return 1
	    return n * fact(n - 1) #注意留意此处。
	                           #retuen的返回值是在返回值里面调用递归函数,引入了乘法表达式

可以看到,return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1和num * product在函数调用前就会被计算,不影响函数调用。

fact(5)对应的fact_iter(5, 1)的调用如下:

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120

尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。

遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

注意:

  1. 使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。

  2. 针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

  3. Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。 所以在计算大的阶乘数据时建议还是使用for循环方式。

4. pycharm社区版怎么显示空格与制表符?

设置如下:

  1. 设置table为4个空格
    在这里插入图片描述
    在这里插入图片描述
  2. 显示出空格
    在这里插入图片描述
    在这里插入图片描述

参考网址:

  1. https://www.liaoxuefeng.com/wiki/1016959663602400/1017268131039072
  2. https://www.jianshu.com/p/efc8a7357588
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值