Python系列教程(二十三):调试代码和函数执行流程

  一、Python调试代码  

1、什么是调试代码

    调试代码是每个程序都不可避免的步骤,我觉得稍微一点复杂的代码不是写出来的,而是一点点调试出来的,所以学会调试代码也很重要,所谓调试代码就是,当程序有错误或者执行结果并非正确的时候,需要借助某种手段,查看程序在某个时间段或者某条语句时,程序在内存中的栈是什么情况,变量是什么值,通过这些变化可以判断你的程序的症结在哪里。

    调试代码也是一门技术活,熟悉各种调试方法,可以快速定位问题点,在python中,一般有两种比较实用的代码调试方法,一种是print大法,一种是通过pycharm工具加断点进行debug

2、pycharm调试代码基本流程

    ① 在你需要调试的语句前面,通过点击鼠标左键加断点,加了断点后代码前面会有一个红色小圆点。

    ② 断点可以有多个

    ③ 在工具栏‘Run’模块中,选择Debug,或者点击‘小甲虫’图标进行调试

    ④ 程序会在你加断点的位置,暂停往下执行

    ⑤ 这个时候通过两个小窗口‘Frames’和‘Variables’查看栈和变量的值

    ⑥ 通过‘F8’继续往下执行到下一个断点处停止,以此类推到程序结束为止。

    1553394023246286.png

  二、函数执行流程分析  

    今天我们就通过调试代码的方式来演示函数在内存中的执行流程。

    下面是一段函数互相调用的演示代码。

def foo1(b, b1=3):
    print("foo1 called", b, b1)

def foo2(c):
    foo3(c)
    print("foo2 called", c)

def foo3(d):
    print("foo3 called", d)

def main():
    print("main called")
    foo1(100, 101)
    foo2(200)
    print("main ending")

main()

第一次调试:在foo1函数进行调试

    ① Frames:栈底是main,栈顶是foo1,很好理解,因为是由main函数调用foo1函数,所以有理所当然的,先把main函数压到栈中,调用foo1的时候,再把foo1压到栈中,就形成这种情况

    ② Variables:可以看到传参的变量,此时b=100,b1=101

第一次调试

第二次调试:在foo3函数进行调试

        ① Frames:首先,我们再来看栈中的情况,前面的foo1已经不见了,这就是出栈,所谓出栈,就是函数foo1调用完成了,就会被弹出栈。再然后按照程序的执行顺序,是先调用foo2的,所以会先把foo2进行压栈,而foo2中又调用了foo3,所以又把foo3进行压栈,最终栈的情况就如下所示。

        ② Variables:可以看到传参的变量,此时d = 200

第二次调试

第三次调试:在foo2函数进行调试

        ① Frames:执行到这里,foo3函数已经执行完成了,所以foo3也被弹出栈了,只剩下main和foo2。

        ② Variables:可以看到传参的变量,此时c = 200

第三次调试

第四次调试:在main函数进行调试

        ① Frames:执行到这里,foo2函数已经执行完成了,所以foo2也被弹出栈了,只剩下main。

        ② Variables:可以看到mani没有传参的变量,所以没有值

第四次调试

  三、函数执行流程总结  

1、函数执行流程

    ① 所谓栈,就是python在内存当中开辟的一块空间,专门用来存放一些函数或者临时数据的,栈的结构特点是先进后出的,你可以想象成一个盒子,最先放进去的东西,如果是一层层拿的,那么肯定是最后才能拿走。

    ② 函数执行的过程就是:压栈 –> 执行 –>弹栈

    ③ 如果函数体内又调用其他函数,依然会把函数再进行压栈,比如:会先把外层函数进行压栈,然后在外层函数的基础上再压内层函数。

    ④ 函数执行完成之后,将会弹栈

    ⑤ 依照栈这种结构,可以想象到,必须得到栈顶的函数弹出栈了,下面的函数才可以执行,如果一直卡在内层函数,外层函数也无法正常执行弹栈。所以要等到内层函数执行完成后,内层函数会先弹出栈,才能再执行外层函数,完成之后再弹出栈

2、压栈和弹栈流程图

函数压栈过程

函数弹栈过程

3、通过栈分析函数作用域本质

    前面学过函数的作用域的时候,也明确指出,函数体内的变量,外部是不可以用的,内层函数的变量外层函数也是不可以用的(不考虑申明global的情况),那么通过压栈和弹栈的学习,应该可以理解作用域原理的本质了,在前面的演示当中,我们可以看到‘variables’存的就是变量的值,这些都是存放在栈中的,而一个函数执行完成之后,就会弹栈,那么里面的数据也会被弹出。所以外层函数或者外部,还能看到么。

Jimmy's Blog ,版权所有丨如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权,转载请注明转自:https://www.xjimmy.com/python-23-function3.html

Leave a Comment