【摘要】
上一篇番外中我们讲解了调试对于编程的重要性,并且介绍了Python中的pdb 工具包,可以帮我们在没有IDE的环境下进行代码调试。
但pdb 终归是基于命令行交互式的,对于刚接触编程的朋友来说并不友好,并且在日常开发中,如果代码架构略微复杂,或者是引用的第三方库,不太了解具体的实现细节,那么pdb 就不是最合适的调试方法了。
那么今天我们就讲解一下最容易上手且很直观的IDE调试方法
【IDE】
集成开发环境(IDE,Integrated Development Environment )是用于提供程序开发环境的应用程序。
一般包括代码编辑器、编译器、调试器和图形用户界面等工具。
集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。
所有具备这一特性的软件或者软件套(组)都可以叫集成开发环境。
目前Python语言中使用最常用的就是Pycharm和VSCode。
今天我们就详细讲解一下如何使用Pycharm进行调试
【Pycharm】
IDE除了显而易见的代码补全功能以外,清晰便捷的Debug功能也是非常重要的,如果你还是只用Pycharm来编辑代码,那可就有点儿暴殄天物了。
这次仍然用pdb 篇中的示例代码为大家讲解
import sys
def foo(num):
ret = []
for i in range(num):
tmp = i ** 2
ret.append(tmp)
return ret
if __name__ == "__main__":
args = sys.argv
result = foo(int(args[1]))
print(args)
在Pycharm中展示如下图
关于Pycharm的其他细节使用不是今天这篇文章的主题,我们就略过不谈,单独了解一下Pycharm的调试功能
一、开启调试
Pycharm开启调试有三种方法
- 当文件中有
if __name__ == "__main__": 时,Pycharm会识别到,并将该行标识为程序入口,用一个绿色的三角形表示。
左键单击该三角形会有一个下拉框,第二个选项Debug 'main' 就是开启调试的按钮
- 在文件空白处右键单击可以弹出下拉选相框,其中同样会有
Debug 'main' 按钮
- 工具栏中有一个虫子符号的按钮,同样也是
Debug 'main' 的按钮
二、断点调试
- 右侧黄色框中点击可以为指定行添加断点,添加断点后程序会执行到断点所在行中断,断点所在行为将要执行的下一行代码
- 我们已经在12行添加了一个断点,现在采取上述任意一种方式开启调试后,Pycharm页面如下图
页面中有几大重要的部分已经通过红框和注释标识出来,我分别对其做一下详细的解释:
变量值:
进行调试一个最主要的目的就是要知道程序运行过程中,定义的变量是如何变化的,他们的值或者类型分别是什么?
Pycharm会在程序代码每行的行尾空白处表明该变量的当前值;
页面下方的Variables框中则会显示更为详细的变量信息,包括变量值,变量具有的属性和方法等;
并且Variables框的左侧有一列按钮可以对变量进行其他操作,最常用的就是添加要Watch的变量,比如我想查看args 的长度,就可以点击黄色框中的加号,输入len(args) 即可, 如下图
调试窗口/输出窗口:
开启调试后默认页面就处在Debugger 调试窗口下,但如果程序中存在打印输出的内容,则需要点击Console 按钮,切换到输出窗口才可以看到输出内容。
调试操作按钮
调试时最主要的几个按钮如下图所示
调试按钮 | 快捷键 | 含义 |
---|
Step Over | F8 | 步进:执行下一行代码 | Step Into | F7 | 步入:执行下一行代码,如果下一行为函数则进入函数 | Step Into MyCode | Alt+Shift+F7(Option+Shift+F7) | 步入:与Step Into功能类似,但只会进入到自己编写的函数中 | Step Out | Shift+F8 | 步出:运行断点后的所有代码,当前如果在函数中,则会返回到上一层 | Run to Cursor | Alt+F9 | 执行到光标:一直执行到光标所在行,当前在循环中时,点击一次会执行一次循环 |
- 继续调试,在12行断点处点击Step Over按钮,会发现程序抛出了异常,如下图:
这个错误的含义是数组的下标超出了范围,从上一步可以看出args = ['./main.py'] ,args 的长度只有1,但12行却要访问args[1] ,表示访问args 的第二个元素,很明显会发生数组越界,所以程序抛出了异常。
这里要求我们通过命令行传入一个参数,但我们目前是直接使用Pycharm的调试按钮启动的程序,如何输入自定义参数呢?如下图
上图中的红框处可以输入参数,相当于命令行执行时python main.py 后面的内容,所以这里输入3,等价于python main.py 3
- 步入函数,现在输入参数后就可以在12行处点击Step Into或者Step Into MyCode按钮进入函数中
一直点击Step Over一行一行执行函数,可以看到当前行执行到第7行,IDE显示第一次循环的i = 0 , 计算得到的tmp = 0
直接点击Run to Cursor,可以执行代码到光标处,因为当前代码执行到了第7行,光标默认位于此处,所以点击Run to Cursor可以直接执行下一次循环到此处,不用点击多次Step Over。
当想要直接结束所处函数的执行,可以点击Step Out,便会执行完函数并返回至上一层
如果存在多个断点的情况,可以直接点击左下角框选的按钮,则会跳转到下一个最近的断点处,如果当前断点之后没有断点则会直接运行完剩余程序。
【Flask示例】
前几天有个朋友提了一个问题,正好可以来为大家演示一下,当不了解程序内部实现时如何使用Pycharm进行代码调试
from flask import Flask
app = Flask(__name__)
if __name__ == "__main__":
app.run()
上面的代码是一段最为简单的启动Flask项目的示例代码
Tips: Flask是使用Python编写的轻量级Web框架,马上我们会出相应的专题
第二行app = Flask(__name__) 的作用是创建一个应用对象实例,app是Flask的实例,Flask接收包或者模块的名字作为参数,但一般都是传递(__name__ ),让flask.helpers.get_root_path 函数通过传入这个名字确定程序的根目录,以便获得静态文件和模板文件的目录。
现在我们使用代码调试试图看看Flask是如何根据__name__ 确定程序根目录的。
在app初始化处加入断点,然后点击Debug开启调试
现在点击Step Into跳进Flask() 函数中
由上图可以看出,Flask类继承了Scaffold类,并且我们当前处于super().__init__() 这一行,这一行表示对父类进行初始化,所以再次点击Step Into步入父类中(由于此处函数参数过长,代码存在换行,所以需要点击多次步入按钮,直到跳入父类中即可)。
由上图可知,现在已经进入到Flask的父类Scaffold的初始化函数中,并且我又点击了几次Step Over,直到运行到上图所在行。
这里就是对项目根目录的确定逻辑,由于我们在初始化app时没有传入root_path 参数,所以当前root_path为None,这样就会用到flask.helpers.get_root_path() 根据传入的import_name 来确定项目根目录。而import_name 就是初始化类时传入的__name__ 。至于get_root_path() 函数中具体如何实现的就留给大家自己探索。
【总结】
IDE的调试功能十分强大,毋庸置疑,如果能够合理运用,一定会在学习之路上让大家事半功倍,VSCode的调试方法我这里没有提到,如果有使用VSCode的朋友想了解它的调试方法,也可以在公众号给我留言,我也会出一篇详细的讲解。
欢迎大家添加我的个人公众号【Python玩转自动化运维】加入读者交流群,获取更多干货内容
|