python 调试

一、 学习

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值