• 回调函数、递归函数


    回调函数、递归函数

    回调函数

    回调函数又叫函数回调,指的是将函数作为参数传递到另外的函数中执行。例如将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
    

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

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

    递归函数

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

    #例子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)
    

    enter description here

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

    当跳出判断后开始return 此时他会return什么呢?
    enter description here

    func(1-1)已经被return 接下来会return什么?
    enter description here

    接着就会return func(2-1) return func(3-1) 最终结果是 return func(3)
    enter description here

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

    下面再来一个例子3

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

    详解一下上面代码的运行过程
    enter description here

    在调用函数本身时,它之后的代码并没有结束,而是在等待条件为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 代码运行后会出现错误
    enter description here
    使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。于是python为了杜绝此类现象,强制的将递归层数控制在了997,也可以进行修改默认递归深度,如果用997层递归都没有解决的问题要么是不适合使用递归来解决。

    作者:YinJay

  • 相关阅读:
    Condition Variables
    Cocos2d-x执行时错误:Cocos2d: Get data from file(xxx.xxx) failed!
    HDU
    Android context空指针异常
    linux c server and client 简单的通信
    UVM:8.4.3 用factory 机制创建实例的接口
    5.4 桥接模式(4.2)
    rac安装_grid安装校验报错之grid未建立信任关系
    git 使用ss5代理
    convmv 解决GBK 迁移到 UTF-8 ,中文 文件名乱码
  • 原文地址:https://www.cnblogs.com/YinJay/p/11100372.html
Copyright © 2020-2023  润新知