Python常用程序调试的简单示例

对python这个高级语言感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编两巴掌来看看吧!

程序能一次写完并正常运行的概率很小,基本不超过1%,总会有各种各样的bug需要修正。有的bug很简单,看看错误信息就知道,有的bug很复杂,我们需要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,因此,需要一整套调试程序的手段来修复bug。下面我们来看下常用的Python调试方法

1. 断点打印发

第一种方法简单直接粗暴有效,就是用print把可能有问题的变量打印出来看看:

err.py


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

def foo(s):
  n = int(s)
  print '>>> n = %d' % n
  return 10 / n
def main():
  foo('0')
main()

# End www.jb51.cc

执行后在输出中查找打印的变量值:


$ python err.py
>>> n = 0
Traceback (most recent call last):
 ...
ZeroDivisionError: integer division or modulo by zero

# End www.jb51.cc

用print最大的坏处是将来还得删掉它,想想程序里到处都是print,运行结果也会包含很多垃圾信息。所以,我们又有第二种方法。

2. 断言

凡是用print来辅助查看的地方,都可以用断言(assert)来替代:

err.py


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

def foo(s):
  n = int(s)
  assert n != 0,'n is zero!'
  return 10 / n
def main():
  foo('0')

# End www.jb51.cc

assert的意思是,表达式n != 0应该是True,否则,后面的代码就会出错。

如果断言失败,assert语句本身就会抛出AssertionError:


$ python err.py
Traceback (most recent call last):
 ...
AssertionError: n is zero!

# End www.jb51.cc

程序中如果到处充斥着assert,和print相比也好不到哪去。不过,启动Python解释器时可以用-O参数来关闭assert:


$ python -O err.py
Traceback (most recent call last):
 ...
ZeroDivisionError: integer division or modulo by zero

# End www.jb51.cc

关闭后,你可以把所有的assert语句当成pass来看。

3. logging日志

把print替换为logging是第3种方式,和assert比,logging不会抛出错误,而且可以输出到文件:

err.py


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

import logging
s = '0'
n = int(s)
logging.info('n = %d' % n)
print 10 / n

# End www.jb51.cc

logging.info()就可以输出一段文本。运行,发现除了ZeroDivisionError,没有任何信息。怎么回事?

别急,在import logging之后添加一行配置再试试:


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

import logging
logging.basicConfig(level=logging.INFO)

# End www.jb51.cc

看到输出了:


$ python err.py
INFO:root:n = 0
Traceback (most recent call last):
 File err.py,line 8,in <module>
  print 10 / n
ZeroDivisionError: integer division or modulo by zero

# End www.jb51.cc

这就是logging的好处,它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。

logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。

4. pdb调试

第4种方式是启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。我们先准备好程序:

err.py


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

s = '0'
n = int(s)
print 10 / n

# End www.jb51.cc

运行:


$ python -m pdb err.py
> /Users/PythonTab/Github/sicp/err.py(2)<module>()
-> s = '0'

# End www.jb51.cc

以参数-m pdb启动后,pdb定位到下一步要执行的代码-> s = '0'。输入命令l来查看代码:

(Pdb) l

1 # err.py

2 -> s = '0'

3 n = int(s)

4 print 10 / n

[EOF]

输入命令n可以单步执行代码:

(Pdb) n

> /Users/PythonTab/Github/sicp/err.py(3)<module>()

-> n = int(s)

(Pdb) n

> /Users/PythonTab/Github/sicp/err.py(4)<module>()

-> print 10 / n

任何时候都可以输入命令p 变量名来查看变量:

(Pdb) p s

'0'

(Pdb) p n

0

输入命令q结束调试,退出程序:

(Pdb) n

ZeroDivisionError: 'integer division or modulo by zero'

> /Users/PythonTab/Github/sicp/err.py(4)<module>()

-> print 10 / n

(Pdb) q

这种通过pdb在命令行调试的方法理论上是万能的,但实在是太麻烦了,如果有一千行代码,要运行到第999行得敲多少命令啊。还好,我们还有另一种调试方法。

pdb.set_trace()

这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点:

err.py


# @param Python常用的程序调试方法
# @author 编程之家 jb51.cc|www.www.jb51.cc 

import pdb
s = '0'
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print 10 / n

# End www.jb51.cc

运行代码,程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行:


$ python err.py 
> /Users/PythonTab/Github/sicp/err.py(7)<module>()
-> print 10 / n
(Pdb) p n
0
(Pdb) c
Traceback (most recent call last):
 File err.py,line 7,in <module>
  print 10 / n
ZeroDivisionError: integer division or modulo by zero

# End www.jb51.cc

这个方式比直接启动pdb单步调试效率要高很多,但也高不到哪去。

5. IDE调试

如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的IDE。目前比较好的Python IDE有PyCharm,

另外,Eclipse加上pydev插件也可以调试Python程序。

 

小结

写程序花费的时间往往要小于调试的时间,这个是基本规律。

虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。断点调试也是高手的终极利器!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


本文适合有 Python 基础的小伙伴进阶学习 作者:pwwang 一、前言 本文基于开源项目: https://github.com/pwwang/python-import-system 补充扩展讲解,希望能够让读者一文搞懂 Python 的 import 机制。 1.1 什么是 import
前言 目前有个python应用需要在容器镜像内拉取git私有仓库的代码,一开始的想法是用GitPython,折腾一番ssh私钥和known_hosts问题后,发现还是在镜像中封装个git最省事,然后用subprocess调用系统命令,镜像体积也没有想象中增加特别多。 准备ssh私钥和known_ho
前言 当网络不稳定或应用页面加载有问题,可以设置等待,避免网络问题导致找不到元素等异常。 隐式等待 隐式等待设置的是最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间结束。 隐式等待在driver的整个生命周期都有效,初始化的时候设置一次即可。 # 隐式等待10秒 drive
前言 map()、reduce()、filter()是python的三个高阶函数。所谓高阶函数,指的是将函数作为参数并返回函数作为结果的函数。下面代码的sing_ready只是一个简单高阶函数示例: def ready(name): return f&quot;ready,{name}!&quot;
入门使用 # 示例代码 warframe = [&quot;saryn&quot;, &quot;wisp&quot;, &quot;volt&quot;] counts = [len(n) for n in warframe] for i,j in zip(warframe,counts): pr
前言 功能描述:批量重命名指定目录下的文件,文件名加前缀,默认格式为“目录名_原文件名”。 示例代码 import argparse import os import sys import logging def gen_args(): &quot;&quot;&quot; 说明 解析命令行参数 &
前言 常见的应用配置方式有环境变量和配置文件,对于微服务应用,还会从配置中心加载配置,比如nacos、etcd等,有的应用还会把部分配置写在数据库中。此处主要记录从环境变量、.env文件、.ini文件、.yaml文件、.toml文件、.json文件读取配置。 ini文件 ini文件格式一般如下: [
前言 在设计API返回内容时,通常需要与前端约定好API返回响应体内容的格式。这样方便前端进行数据反序列化时相应的解析处理,也方便其它服务调用。不同公司有不同的响应内容规范要求,这里以常见的JSON响应体为例: { &quot;code&quot;: 200, &quot;data&quot;: {
前言 我们一般使用如下方式点击元素: elem = driver.find_element(...) elem.click() # 或者使用带等待条件的方式 elem = WebDriverWait(driver, 10).until(EC.xxx(...)) elem.click() 正常情况下,
前言 从环境变量和配置文件中获取配置参数,相关库: python-dotenv:第三方库,需要使用pip安装 configparser:标准库 示例代码 test.ini [mysql] host = &quot;192.168.0.10&quot; port = 3306 user = &quot
前言 Relative Locators,相对定位器,是Selenium 4引入的一个新的定位器,相对定位器根据源点元素去定位相对位置的其它元素。 相对定位方法其实是基于JavaScript的 getBoundingClientRect() 而实现,简单的页面还行,复杂页面中可能会定位到需要相同类型
简介 The pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and librari
简介 Faker库可用于随机生成测试用的虚假数据。 可生成的数据参考底部的参考链接。 安装: python -m pip install faker 快速入门 from faker import Faker # 实例化一个对象,本地化使用中国 fk - Faker(locale=&quot;zh_C
前言 原本应用的日志是全部输出到os的stdout,也就是控制台输出。因其它团队要求也要保留日志文件,便于他们用其他工具统一采集,另一方面还要保留控制台输出,便于出问题的时候自己直接看pod日志。具体需求如下: 日志支持同时控制台输出和文件输出 控制台的输出级别可以高点,比如WARNING,个人这边
按列从多个文件中构建 假设有两个csv文件,列不相同,需要整合为一个dataframe,使用glob模块: from glob import glob import pandas as pd # glob会返回任意排序的文件名,所以需要sort排序 some_files = sorted(glob(
简介 diagrams是python的一个第三方库,用于实现使用代码绘制架构图。 安装 依赖于 Graphviz,安装diagrams之前需要先安装 Graphviz(下载压缩包后,将bin目录添加到系统环境变量Path里即可)。 python3 -m pip install diagrams 快速
前言 最近有个个人需求是要把多个图片文件合并为一个PDF文件,这样方便用PDF阅读器连续看,避免界面点一下,只会图片放大。(比如看漫画) 主要思路是先把单张图片转换成单个PDF文件,然后把PDF文件进行合并。原先是用WPS的转换工具做的,但WPS每次只能批量转换30张,如果有大量图片文件,用WPS就
前言 版本: python:3.9 selenium:4.1.5 获取元素文本 text = driver.find_element(by=By.XPATH, value=&quot;&quot;).text 获取元素属性值 attr1 = driver.find_element(by=By.XPA
Python中有个内置的函数叫做 enumerate,可以在迭代时返回元素的索引。 # 示例代码01 warframe = [&quot;saryn&quot;, &quot;wisp&quot;, &quot;volt&quot;] for i,name in enumerate(warframe
前言 版本: python:3.9 selenium:4.1.5 浏览器:firefox 创建浏览器对象 from selenium import webdriver driver = webdriver.Firefox(executable_path=r&quot;C:\software\sele