目录
一、 学习
1.1、 print
print 大法好,是我在开发代码的时候经常用的,很方便,比如某些变量不合你的预期,就可以打印下试试
用print()最大的坏处是将来还得删掉它,想想程序里到处都是print(),运行结果也会包含很多垃圾信息,而且如果 print 加的多,也挺烦的
1.2、 logging
import logging 的方式,生产上用的多
1.3、 assert
assert 例子
#!/usr/bin/env python
# coding=utf-8
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('10')
if __name__ == '__main__':
main()
此时执行 python test_asert.py,不会输出任何东西,如果把调用的位置改成 foo(‘0’)
#!/usr/bin/env python
# coding=utf-8
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
if __name__ == '__main__':
main()
执行结果如下:
(base) ➜ python_debug python test_asert.py
Traceback (most recent call last):
File "test_asert.py", line 13, in <module>
main()
File "test_asert.py", line 10, in main
foo('0')
File "test_asert.py", line 6, in foo
assert n != 0, 'n is zero!'
AssertionError: n is zero!
assert n != 0, ‘n is zero!’
这句话表明的含义是,如果 n!=0, 程序会继续往后走,否则会打印日志并且抛异常,如果程序中到处充斥着assert 好像也不太好看,索性可以在启动时 python -O 屏蔽掉 assert 语句
二、实战
我是在实践中遇到这么一个问题,我调用一个 url , 这个 url 一直卡在那里,我就很懵逼,因为我要测试啊,但是代码都不往下面走,当时我是采用了2种方法,一种自然是 print ,我在很多地方都加了print,我想知道程序到底卡在了哪里,虽然感觉很 low 逼,但确实很实用,一种是用 pycharm 进行调试
print 就是需要在代码中添加很多print,导致代码非常乱,现在想想最好的还是 pycharm 和 gdb,pycharm 可以直接打断点,不需要添加额外代码,gdb就更好了,直接可以杀一个 core文件,看看python程序当前是卡在哪里,pdb 感觉优势也不是很强,仍然需要在代码中手动添加代码,其实相当于是通过代码打断点
但无论是哪种方式,我们都需要用经验来判断,程序卡在了哪里
2.1、 利用 pycharm
首先,根据经验打断点,因为url一进来就有2处连接数据库的地方,我怀疑是这里卡主了,在这前后打个断点,打断点的方式是直接左侧空白右击即可,如下图所示:
有红点表示当前位置设置了断点,有红点那一行还是蓝色,说明程序当前正停在这一行,前提是你得开启debug运行模式
当我按F9表示程序继续运行,但是并没有把下一个断点处标记为蓝色,如下图:
说明程序卡在两个红色断点之间,同时也发现左侧的Debugger 区域是一篇空白,那么问题就基本定位到了,而图中那么多 print 就是我用 print 大法,需要不断的打日志,尝试卡主的位置
当你去查看pycharm 的run 菜单,里面会有很多调试方法,比如单步运行、进入函数之类的,以后需要用到时,再仔细看看,先简单列举下常用的
命令 | 功能 |
---|---|
step over(F8) | 单步步过(会直接执行完该函数)在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止 |
step into(F7) | 单步步入(会跟踪到函数内部去,如果函数内部调用了其他函数或模块,则又会跟踪到其他的函数或者模块当中),源码中也可以跳入 |
step out(Shift+F8) | 返回上一层函数 |
Step Into My Code | 只会进入到自己写的代码中 |
其实完全可以借助于pytharm 定位大致问题,再使用print 大法
打印变量
debug 模式,先点击 Console,然后再点击Show Python Prompt,如下:
接下来出现如下界面,就可以执行python 代码了,比如你要查看变量等,如下:
这个不得不说真的是太完美了
2.2、pdb
我感觉如果可以借助于 pycharm 调试,pycharm 是首选,但 pdb 也有其适用场景,比如需要直接在生产环境写代码,调试时,无法借助于 pycharm ,就必须得用到 pdb
pdb 有两种使用方式,一种是按平时的方式运行 python 程序,但调试是,需要在python 程序中引入 pdb 包,并以代码的方式设置断点,另一种方式,是以类似 python -m pdb err.py 的方式 运行python 程序,程序以启动就会进入调试模式,但第二种方式可能对于提供服务的python 程序来说,可能并不适用
2.21 方式一
首先需要 import pdb,然后用 pdb.set_trace() 在对应的位置设置断点如下:
然后正常的运行主程序,如下:
(base) ➜ real_sim_alg_eva python main.py
2022-02-18 17:58:38,184 31451:4723785152 tool_mysql.py[line:41] INFO cfb_day_hot_recommend run begin at 2022-02-18 17:58:38.184475
2022-02-18 17:58:38,956 31451:4723785152 __init__.py[line:276] DEBUG $HOME=/Users/songbw
2022-02-18 17:58:38,956 31451:4723785152 __init__.py[line:276] DEBUG CONFIGDIR=/Users/songbw/.matplotlib
2022-02-18 17:58:38,956 31451:4723785152 __init__.py[line:276] DEBUG matplotlib data path: /Users/songbw/opt/anaconda3/lib/python3.7/site-packages/matplotlib/mpl-data
但是会打印很多程序本身的日志,只有当你走到了断点的位置,才会进入pdb模式,如下我调用了下接口,就进入pdb模式了,如下:
2022-02-18 17:58:43,491 31451:123145509756928 loadData.py[line:259] INFO state_id start cal through redis.[24-0001]
enter robot interface.
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(87)robot()
-> logging.debug("enter robot interface.")
(Pdb) l
82 # projectId = projectid
83 # sessionId = session_id
84 # question = question
85 print ("enter robot interface.")
86 pdb.set_trace()
87 -> logging.debug("enter robot interface.")
88
89
90 inputJson = request.args
91
92 projectId = inputJson.get("productKey", '') # 根据projectId 加载此配置文件,redis维护当前用户信息
(Pdb) p question
*** NameError: name 'question' is not defined
(Pdb)
此时就可以执行一些简单的命令了
命令 | 描述 |
---|---|
l | 查看当前的代码块 |
n | 单步运行 |
c | 继续运行 |
p | 查看当前变量 |
如下是一些命令的使用:
2022-02-18 17:58:43,491 31451:123145509756928 loadData.py[line:259] INFO state_id start cal through redis.[24-0001]
enter robot interface.
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(87)robot()
-> logging.debug("enter robot interface.")
(Pdb) l
82 # projectId = projectid
83 # sessionId = session_id
84 # question = question
85 print ("enter robot interface.")
86 pdb.set_trace()
87 -> logging.debug("enter robot interface.")
88
89
90 inputJson = request.args
91
92 projectId = inputJson.get("productKey", '') # 根据projectId 加载此配置文件,redis维护当前用户信息
(Pdb) p question
*** NameError: name 'question' is not defined
(Pdb) n
2022-02-18 18:07:12,289 31451:123145515012096 main.py[line:87] DEBUG enter robot interface.
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(90)robot()
-> inputJson = request.args
(Pdb)
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(92)robot()
-> projectId = inputJson.get("productKey", '') # 根据projectId 加载此配置文件,redis维护当前用户信息
(Pdb) p inputJson
ImmutableMultiDict([('productKey', '5'), ('sessionKey', 'abcdefghijkfs'), ('question', '@start@')])
(Pdb) p projectId
*** NameError: name 'projectId' is not defined
(Pdb) n
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(93)robot()
-> sessionId = inputJson.get('sessionKey', '')
(Pdb) p projectId
'5'
(Pdb) c
> /Users/songbw/hengchang/Similarity_algorithm_evaluation/real_sim_alg_eva/main.py(95)robot()
-> question = inputJson.get('question', '')
(Pdb)
(Pdb) 2022-02-18 18:08:25,311 31451:123145509756928 loadData.py[line:264] INFO state_id end cal.[24-0001][581]
2022-02-18 18:08:25,323 31451:123145509756928 loadData.py[line:280] INFO gloabl intend_id start cal.
综上还是感觉 pycharm 是首选,对于自己的开发环境来讲
2.22 方式二
如下 service2.py 是服务端的代码,我用第二种方式调试,程序一启动,直接进入调试模式,然后我在文件 service2.py 的第33行设置了断点,然后我继续运行,让服务端启动
紧接着,我客户端去调用服务端的接口,并没有停下来进入调试模式
结论
对于非服务端的 python 代码,方式二的调试方式,有其优势,因为不用多加额外代码,但是,对于服务端的代码调试可能不太支持,也可能还有一种方法,我不知道
2.3、gdb
之所以考虑 gdb 调试,是因为之前线上遇到一个 redis 消费卡住的问题,心想要是 python 程序也支持 gdb,直接杀一个 core 文件,看看是否是 redis 线程卡住了,应该很快就定位到问题了,结果查了下,python 还真支持 gdb 调试,所以就进行了些尝试
尝试了下,用 gdb 去关联 /root/anaconda3 下的 python 包,但在手动编译时 gdb 出错,报在我的/root/anaconda3 下面没有可用的 python3,要解决这个问题,感觉得看 编译的源码,所以一直拖着,先搁置吧
未来可能尝试下,直接在系统上装 python,不用conda,可能关联 gdb 那里可能会简单些
2.4、dtrace
待研究,需要用时再搞
2.5、traceback 包
我们生产代码也用 python traceback 包,待研究
gdb, 可以参考
感觉够用了
貌似有点用
再说gdb 的牛逼之处
参考文献:
[1] 讲了python 几种调试的方式
[2] 看着像官网
[3] 感觉融汇了各种调试方法
[4] 官网的pycharm调试
[5] 打印变量
[6] 关于 dtrace
[7] 关于dtrace 2
[8] 关于gdb 调试python 1
[9] 关于gdb 调试python 2
[10] 关于gdb 调试python 3
[11] 关于gdb 调试python 4