python的递归函数和lambda表达式

1. Recursion function

1.1 概念

在定义一个函数的时候,在函数内部直接或者间接的调用了本省这个函数,就称为递归函数。

def test():
    ...
    return test()

这个函数直接调用了自身。定义了test这个函数,它的返回值是test(),就是说调用了test()的返回值,但是test()的值是test(),这样来回不断地调用函数,如果没有结束条件,就是一个死循环,不过也是递归。

def a():
    ...
    b()
    ...
    return ...

def b():
    ...
    return a()

这种在函数内部调用了某一个函数,这个被调用的函数内部又调用了原函数,这样叫间接调用,经常出现死循环,而且错误不好查找。

1.2 要求

递归函数一定要间接或者直接的调用自身

递归函数一定要有边界条件,不能无休止的递归。
不满足这个边界条件是,递归继续,函数执行,
满足这个边界条件时,递归停止,函数结束。

递归函数的层数不宜过多,递归层数太多的话会引起效率问题。python对递归函数的深度(层数)做了限制。不过限制的层数可以手动调整。

1.3 例子

求n的阶乘,是一个明显的可以用递归函数解决的问题:

def accumlate(n, outcome=1):

    if n < 2: #这里是边界条件,当实参n小于2时,就返回outcom
        return outcome

    else:
        outcome *= n
    return accumlate(n-1, outcome) 
    #这里是迭代,如果没到边界条件,每次都返回此函数,
    但是实参每次都改变。

还有一个典型的可以用递归函数的是fibonacii sequence:

def fibnacii(n, a=1, b=1, seq=None):

    if seq is None: #这么写是想练一练这个技巧
        seq = []

    if n < 3: #这是边界条件
        if n == 1:    #如果实参给的1,那么就是[1],特殊情况
            return [1]
        else:     #如果给的是2,也是特殊情况,如果直接给2,seq是[]
            return [1,1] + seq
    else:    
        a, b = b, a + b     #和循环一样的思路,三个数子a, b, a+b来回换
        seq.append(b)
        return fibnacii(n-1, a, b, seq) 
        #迭代,每次迭代n都要减1,然后把新算的a, b(其实是a+b) 
        覆盖原有的a, b,把append好的seq传入。

2. 调用栈

2.1 基本概念

函数在执行的时候,会用到调用栈这个数据结构。

栈,stack,特点是后进先出。栈和多线程有关,每一个线程有一个栈,不同的线程之间互不干扰。

可以把栈想象成一叠便条,以下面这个函数为例:

扫描二维码关注公众号,回复: 3111910 查看本文章
def main(string): #这些string都是形参,品品
    print(string)
    def inner(string):
        print(string)
    return inner(string)

调用这个函数,就会形成一个调用栈:

main('fuck')

首先,把一张main()函数的便条,放在桌子上;
再压上main()要用的数据 ‘fuck’ 的便条;
再压上print()函数的便条;

执行main的print(‘fuck’),执行结束后撕掉。现在只剩一个main()函数的便条。

又调用了inner()函数,就是再在main()函数上压上inner()便条;
再压上inner()要用的数据 ‘fuck’ 的便条;
再压上print()函数的便条;

执行inner的print(‘fuck’),执行结束撕掉。现在只剩一个main()函数的便条。

执行全部结束了,把main()函数的便条也撕掉。

往上压便条,就叫做压栈,撕掉便条,就叫弹出栈,比如一个局部变量在函数内部调用时创建,就是压栈,调用结束后消亡,就是从栈弹出,所以在外部找不到这个局部变量了。

栈内的一条语句和数据执行完,就弹出,然后往下走根据代码压栈-执行-弹出。

2.2 栈的深度

递归函数在创建调用栈时,因为是不断地调用自身,所以调用栈会压入很多层,所以说递归函数的性能很差。

python的调用栈有层数限制,可以更改,但最好不要更改,可以通过sys模块下的getrecursionlimit()来查看:

import sys
print(sys.getrecursionlimit())

这个深度界限用代码计数的话可能不符,因为这个函数执行,可能还需要先压入别的函数和数据。

3. lambda表达式

python中有一种函数,他没有名字,只能写在一行里。也叫做匿名函数。

格式如下:

lambda 参数列表:表达式
(lambda 参数列表:表达式)(实际参数)

lambda x, y: x**2 + y**3 #这是函数的定义

fn = lambda x, y: x**2 + y**3 #,可以用标识符来接,然后调用
fn(2, 3)
31

(lambda x, y: x**2 + y**3)(2, 3) #也可以这么调用
31

这种lambda表达式定义的函数,在高阶函数中运用十分广泛。

lambda表达式的返回值就是表达式的结果。

lambda表达式里不能出现赋值语句。

猜你喜欢

转载自blog.csdn.net/LittleHuang950620/article/details/82153984