Python爬虫、数据分析与可视化:工具详解与案例实战
上QQ阅读APP看书,第一时间看更新

1.4 return的重要性——函数的递归调用

在定义和使用函数时,如果仅仅在函数体内部修改参数值,而不用return返回,那么在调用时就无法得到更新后的数值,甚至还会得到None。在如下的FuncBadUsage.py案例中,我们演示这一效果。


01 def addSalary(currentNum):
02     currentNum = currentNum + 1000
03     # return currentNum
04 print(addSalary(5000)) # None

在第1行里,我们通过def定义了名为addSalary的函数,它有一个名为currentNum的参数。在第2行里,给currentNum变量加1000。注释掉第3行的return语句。

当我们在第4行调用addSalary方法时,打印的结果是None,这是因为addSalary方法没有通过return返回结果。如果我们打开第3行的注释,在方法结尾用return返回结果,那么在第4行调用addSalary方法时就能看到预期的结果6000。

在一个函数内部调用本函数属于递归调用。在如下的FactorialDemo.py案例中,我们将以阶乘演示函数递归调用的做法。


01 def factorial(num):
02     if(num==1):
03         return 1
04     return num * factorial(num - 1)
05 print(factorial(3)) # 6

在第1~4行的factorial函数里,我们实现了递归调用,具体做法是:在第2行判断num是否是1,若是则返回1,否则在第4行递归调用factorial(num-1)。

在第5行里,调用factorial方法的参数是3,根据定义会递归调用3*factorial(2),而factorial(2)则会递归调用2*factorial(1),由于factorial(1)有明确的返回值1,因此递归结束,随后向上推得factorial(2)等于2、3*factorial(2)等于6,由此得到最终结果。

至此,大家应该能理解递归函数的实现方式了。虽然通过递归的写法能提升代码的可读性,但是在使用时务必注意如下两点。

第一,明确定义递归的结束条件。比如在上述案例中,通过第2行和第3行的定义,让num等于1时递归调用结束,并返回1。如果没有结束条件,就会出现无限递归的情况。

第二,计算机操作系统支持的递归层数是有限的,在使用时一定得慎重,因为递归层数过多会产生异常,从而终止程序的运行。也就是说,除非能明确得知递归的层数不会太大,否则别用递归。

为了避免因递归导致的异常,不少项目组干脆禁用递归,或者定义一个比较小的阈值,比如只有明确知道递归层数小于10才能使用。在禁用递归的情况下,我们可以通过循环来实现相同的功能,比如在如下代码里通过循环实现阶乘效果。


01 def factorialByLoop(num):
02     start = 1
03     result = 1
04     while start <= num:
05         result = result * start
06         start = start + 1
07     return result
08 print(factorialByLoop(5)) # 120