回调函数递归函数

Posted cany

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回调函数递归函数相关的知识,希望对你有一定的参考价值。

回调函数、递归函数

回调函数

回调函数又叫函数回调,指的是将函数作为参数传递到另外的函数中执行。例如将A函数作为参数传递到B函数。然后在B函数中执行A函数。这种做法的好处是在函数被定义之前就可以使用函数,或者对于其他程序提供的API(可看成函数)进行调用。概念比较抽象,看下面例子:

def func(num,fun):
    fun(num)

def f1(x):
    print("这是f1函数",x)

def f2(x):
    print("这是f2函数",x)

func(1,f1)
func("hello",f2)

结果

这是f1函数 1
这是f2函数 hello

技术图片
上图是有三个函数内存地址,下面我们开始运行第一个函数调用

首先以位置传参到另外的函数变量中,此时num = 1 fun = f1 函数内存地址指向刚才定义f1函数的内存地址,再往下运行就会实现print 这是f1函数 1
技术图片

递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数,下面例子就是调用自身。

#例子1
def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)

运行下面代码

#例子2
def func(num):
    print(num)
    if num > 0:
        func(num -1)
    else:
        print('--------')
    return num

res = func(3)
print(res)

技术图片

每一次函数调用都会产生一个属于它自己的名称空间,如果一直调用下去,就会造成名称空间占用太多内存的问题。
技术图片

当跳出判断后开始return 此时他会return什么呢?
技术图片

func(1-1)已经被return 接下来会return什么?
技术图片

接着就会return func(2-1) return func(3-1) 最终结果是 return func(3)
技术图片

相信看到这里都有点蒙,这么想,大部分人在做事情的时候,中断第一件事,被安排去做第二件事的时候,就会把第一件事后续的事情给忘记,如果在做第二件事的时候,又被中断,被安排去做第三件事,就会把第一件、第二件要做的后续的事情给忘记......,这就是不理解递归函数的原因。

下面再来一个例子3

def age(n):
    if n == 1:
        return 40
    else:
        return age(n-1)+2

print(age(4))

详解一下上面代码的运行过程
技术图片

在调用函数本身时,它之后的代码并没有结束,而是在等待条件为False 时,再接着执行之后的代码,同一个颜色的print()语句等待对应颜色的函数。

Starting var:.. n = 4
23:14:57.157933 call         4 def age(n):
23:14:57.157933 line         5     if n == 1:
23:14:57.157933 line         8         return age(n-1)+2
    Starting var:.. n = 3
    23:14:57.157933 call         4 def age(n):
    23:14:57.157933 line         5     if n == 1:
    23:14:57.157933 line         8         return age(n-1)+2
        Starting var:.. n = 2
        23:14:57.157933 call         4 def age(n):
        23:14:57.158934 line         5     if n == 1:
        23:14:57.158934 line         8         return age(n-1)+2
            Starting var:.. n = 1
            23:14:57.158934 call         4 def age(n):
            23:14:57.158934 line         5     if n == 1:
            23:14:57.158934 line         6         return 40
            23:14:57.158934 return       6         return 40
            Return value:.. 40
        23:14:57.158934 return       8         return age(n-1)+2
        Return value:.. 42
    23:14:57.158934 return       8         return age(n-1)+2
    Return value:.. 44
23:14:57.158934 return       8         return age(n-1)+2
Return value:.. 46

看上面的过程,当n=1时,直接返回40 此时内存中 age(1) 就产生了。下面它就会把倒数第二件事做完,那就是age(2-1)+2。现在内存中已经有age(1)=40 了,那么age(1)+2=age(2)=42,且age(2)存在内存中,以此类推!

age(3-1)+2=age(3)=44
age(4-1)+2=age(4)=46

最终返回值是46

例子1 代码运行后会出现错误
技术图片
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。于是python为了杜绝此类现象,强制的将递归层数控制在了997,也可以进行修改默认递归深度,如果用997层递归都没有解决的问题要么是不适合使用递归来解决。

以上是关于回调函数递归函数的主要内容,如果未能解决你的问题,请参考以下文章

关于回调和递归思想的理解

Javascript 中的回调函数和递归函数简单实际分析学习

JavaScript函数进阶回调函数递归函数闭包函数

JavaScript-函数(调用参数returnarguments匿名回调递归函数)函数案例

JavaScript 函数进阶函数(匿名回调递归函数)及相关练习

python函数基础3--闭包 + 递归 + 函数回调