本章的主题为调试手段,这是程序开发必不可少的步骤,也是占用时间最多的环节。在程序员的正常开发工作中,调试工作至少占据1/3的时间,而实际编码工作相对占用实际比较少。因此,无论您是初学者,还是编程兴趣爱好者,调试手段一定要学习。

7.1 异常信息

在前面学习过程中,我们看到过经常出现异常打印,比如像下面的代码。代码中执行了Dic.viewkeys()的方法,但是解释器给出了一个Traceback提示,字典对象dict没有viewkeys()属性。意思很直白,就是字典没有viewkeys()这样的操作,那么我们就可以去确认是否有字母写错了,或者甚至确实没有该方法。顺着这样的思路,我们就能找到问题的原因,亦或者在百度中搜索下面的错误信息,看看是否其他也遇到过类似的错误。我们需要知道,我们正在走的路一定是别人走过的,别人也肯定遇到过我们类似的问题,从而少走弯路,浪费时间。

>>> Dic.viewkeys()Traceback (most recent call last):File "", line 1, in AttributeError: 'dict' object has no attribute 'viewkeys'

此外,一旦程序运行过程中遇到这种错误输出,也是在提示我们问题发生的相关信息,以帮助我们定位问题。从下面的Traceback我们可以看到,问题出在tornado-main.py文件的第6行,通过对比代码,我们就能找到出错代码行,从而解决问题。

HTTPServerRequest(protocol='http', host='127.0.0.1:8000', method='GET', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1')Traceback (most recent call last):File "C:甥敳獲ornadoweb.py", line 1699, in _executeresult = await resultFile "C:甥敳獲ornadogen.py", line 191, in wrapperresult = func(*args, **kwargs)File "F:/05_Github/tornado/tornado-main.py", line 16, in getraise Exception("Debug")Exception: Debug

那么,如果我们能够提前预判,可能会存在这样那样的异常,能否通过某种方法来捕获该异常,从而让程序正确的处理遇到的问题。以免程序直接崩溃,导致使用感受差。

接下来,先通过一个代码段来了解如何捕获异常,并进行必要的处理。代码中于Redis数据库建立连接,但是并不知道是否成功,因此需要通过ping()方法进行确认。但是如果连接建立失败了,在ping()的过程中就会抛出异常,那么可以通过try,except进行捕获异常,并进行相应的后处理。比如下面代码,当出现超时错误时,我们记录一个日志打印,并返回一个None给调用者。如若是超时之外的其他错误,则全部记录日志并返回None。这样程序使用者在遇到问题的时候,就能够知道到底是什么原因导致失败,从而及时正确的解决问题。

pool = redis.ConnectionPool(host=ip, port=port, decode_responses=True)r = redis.Redis(connection_pool=pool)logging.debug(r)try:r.ping()logging.debug('ping success')return rexcept TimeoutError:logging.error('redis connection timeout ' + ip)return Noneexcept:logging.error("redis don't exist ")return None

所以,如果我们提前知道某段程序可能会出现异常,那么让该段程序处于try之中。下面的代码段中,当检测到异常时,进行了一些后处理操作,删除了一些临时文件,并记录日志。在下次使用的时候,程序就能够从错误中恢复正常。

user_name = Nonetry:s = shelve.open('user_data', writeback=True)user_name = s['username']s.close()except:path = Path.cwd() #Path('.')for p in path.glob(f"user_data.*"):p.unlink()logging.error("get_user_name, cannot open user_data to get username")return user_name

7.2 日志调试

日志调试是一个最基本的手段,可以让我们了解程序的执行过程,从而确定程序是否按照我们的预想中运行。一般在程序调试中,我们会通过print添加一些临时打印信息,以便及时确认问题,问题确认后再将其删除。

对于一些程序运行过程中的关键信息,我们可能希望即使程序发布了也要记录。那么,logging模块是一个非常不错的选择,可以分级记录日志,并记录到日志文件中。

7.2.1 print打印

print打印应该是程序调试过程中普遍使用的方法,添加很方便,也没有依赖,并能够及时的输出到控制台上。

try:  mail_server = smtplib.SMTP_SSL('smtp.office365.com')  mail_server.ehlo()  mail_server.starttls()  mail_server.ehlo()  mail_server.login(sender, PASS_WORD)  mail_server.send_message(msg)  mail_server.quit()  print("success")except smtplib.SMTPRecipientsRefused:print('邮件发送失败,收件人被拒绝')except smtplib.SMTPAuthenticationError:print('邮件发送失败,认证错误')except smtplib.SMTPSenderRefused:print('邮件发送失败,发件人被拒绝')except smtplib.SMTPException:print('邮件发送失败, ', e.message)

7.2.2 logging模块

logging模块正如其名,是用来记录日志的,可以灵活设置帮助记录程序运行过程或辅助定位问题。支持不同的日志等级,可以很方便的设置级别,使调试版本和发布给别人的版本使用不同的日志级别。可以将日志打印在窗口,也可以保存在日志文件中。还可以自定义日志信息的格式,使其更易于阅读。

我们的程序中将定义如下日志信息格式,及具体使用的方法。通过logging.debug(),logging.info()和logging.error()等不同接口来记录日志信息。我们这里设置的level为logging.INFO级别,因此DEBUG级别的信息不会在日志中出现。当需要调试定位问题时,可以将日志级别修改为DEBUG,则所有日志信息都会被保存。

下面代码是我们程序中使用logging的代码片段。

def repair_core_dump_file(self, dump_file, core_file):sp = [0, 0, 0, 0]lr = [0, 0, 0, 0]pc = [0, 0, 0, 0]self.get_reg_from_dump_file(dump_file, 13, sp)self.get_reg_from_dump_file(dump_file, 14, lr)self.get_reg_from_dump_file(dump_file, 15, pc)logging.info("sp: 0x{}".format(''.join(sp)))logging.info("lr: 0x{}".format(''.join(lr)))logging.info("pc: 0x{}".format(''.join(pc)))with open(core_file, 'rb') as coreHandle:content_by_hex = coreHandle.read().hex()rs = content_by_hex.rfind(''.join(sp))if rs != -1:content_by_hex = content_by_hex.replace(''.join(sp) + '0000000000000000',''.join(sp) + ''.join(lr) + ''.join(pc))with open('repaired-' + core_file, 'wb') as new_coreHandle:content_by_binary = binascii.unhexlify(content_by_hex)new_coreHandle.write(content_by_binary)logging.info("Position:{} is {}".format(rs, content_by_hex[rs:rs + 8]))logging.info("Position:{} is {}".format(rs, content_by_hex[rs + 8:rs + 16]))logging.info("Position:{} is {}".format(rs, content_by_hex[rs + 16:rs + 24]))logging.info("content_by_hex = {}".format(content_by_hex))logging.info("SP000 hint count: {}".format(content_by_hex.count(''.join(sp) + '0000000000000000')))logging.info("sp hint count: {}".format(content_by_hex.count(''.join(sp))))

logging模块也支持将日志信息输出到控制台,需要进行一些必要的配置。

下面再看一段日志文件内容,我们的程序日志文件就像下面这样。

2019-09-03 15:41:42 Tue root INFO login success2019-09-03 15:41:42 Tue root INFO current_version: v2.02019-09-03 15:41:43 Tue root ERROR get_user_name, cannot open user_data to get username2019-09-03 15:41:43 Tue root ERROR get_user_name, cannot open user_data to get username2019-09-03 15:41:43 Tue root ERROR get_user_name, cannot open user_data to get username2019-09-03 15:42:04 Tue root INFO v2.0, maybe server don't running.2019-09-03 15:42:23 Tue root ERROR get_user_name, cannot open user_data to get username2019-09-03 15:42:23 Tue root ERROR get_user_name, cannot open user_data to get username2019-09-03 15:42:23 Tue root ERROR get_user_name, cannot open user_data to get username

7.3 IDE的调试器

在我们编写Python程序的过程中,通常都会使用一定的IDE,比如Pycharm,spyder或者其他类似Python程序开发IDE。都支持集成了调试器,在调试器模式下,我们可以给程序打断点。

如果我们希望程序运行到某行的时候暂停下来,那么可以在该行设置一个断点。同时也支持单步调试,能够看到程序执行过程中每个变量的值的变化,可以说是我们调试程序的终极手段。

由于每个IDE的调试器的具体调试大同小于,这里不针对具体的IDE进行介绍。读者在使用自己的IDE时,可以根据IDE的手册进行必要的学习。

7.4 小试牛刀

在程序开发调试的过程中,可能需要多种调试手段结合着使用。但在程序发布后,我们很难通过控制台打印或者IDE的调试器进行定位问题。那么,最好的选择就是通过日志文件记录程序行为,在问题发生后我们可以通过日志文件确认问题。

如下所示,可以将日志信息记录到日志文件中。程序出现异常后,可以通过日志文件来定位问题发生的原因。

log_name = 'booking-testline.log'logging.basicConfig(level=logging.INFO, #这里表示INFO级别以上的日志信息会被存入日志文件format="%(asctime)s %(name)s %(levelname)s %(message)s",datefmt='%Y-%m-%d %H:%M:%S %a',filename=log_name,filemode='a')

logging.debug('ping success') #DEBUG级别的日志信息是不会被存入日志文件

logging.error("redis don't exist ") #ERROR级别的日志信息会被存入日志文件

7.5 本章小结

本章介绍了一些简单的程序调试手段,也是最基本的调试手段。通过添加print打印,查看Traceback信息,记录日志文件和IDE的调试器,多种手段来调试定位程序问题。正如开题提到的,程序的调试过程将占据整个程序开发周期的大多数时间,因此这是一个必备手段。任何程序都不可能一次编写成功,因此调式是必不可少的步骤。


欢迎关注,转发,收藏

Python实用案例编程入门:第一章 Python概述及为什么学Python

Python实用案例编程入门:第二章 字符串

Python实用案例编程入门:第三章 列表和元组

Python实用案例编程入门:第四章 字典和文件

Python实用案例编程入门:第五章 函数和类

Python实用案例编程入门:第六章 控制流语句

python编程求圆的面积案例_Python实用案例编程入门:第七章 调式手段相关推荐

  1. python编写代码求圆的面积_【Python】求圆的面积,书上的代码可执行却是0,不知道为什么...

    首页 专栏 python 文章详情 0 求圆的面积,书上的代码可执行却是0,不知道为什么 唐代芙发布于 今天 01:27 include define PI 3.14159 double Area(d ...

  2. java设计求圆的面积周长的代码_java编程 1.设计一个求圆的面积和周长的类,要求:1计算当半径r=10和20时,圆的面积,并显示出来 、...

    导航:网站首页 > java编程 1.设计一个求圆的面积和周长的类,要求:1计算当半径r=10和20时,圆的面积,并显示出来 . 时间:2018-11-8 java编程 1.设计一个求圆的面积和 ...

  3. 编程求圆的面积和周长(c语言)

    题目描述: 输入圆的半径(r),求圆的面积(s)和周长(c) 定义圆周率为如下宏常量 #define pi 3.1415 输入: 输入半径r的值 输出: 输出一行,分别为面积s和周长c 样例输入: 1 ...

  4. python电脑编程求圆的面积案例_学Python划重点七 网络编程(UPD Socket编程、上传文件实例、计算圆的面积实例)...

    一.UPD Socket 编程 socket 对象中与UDP Socket 服务器编程有关的方法是bind() ,注意不需要listen() 和accept() , 这是因为UDP 通信不需要像TCP ...

  5. python编程圆面积_python如何求圆的面积

    首先我们要知道圆的面积计算公式:S = πr²,公式中S为所求圆的面积,π为圆周率,r为圆的半径. 示例: # 定义一个方法来计算圆的面积 def findArea(r): PI = 3.142 re ...

  6. python输入圆的半径、输出圆的面积_python如何求圆的面积

    首先我们要知道圆的面积计算公式:S = πr²,公式中S为所求圆的面积,π为圆周率,r为圆的半径. 示例: # 定义一个方法来计算圆的面积 def findArea(r): PI = 3.142 re ...

  7. python输入圆的半径输出圆的面积_python如何求圆的面积

    首先我们要知道圆的面积计算公式:S = πr²,公式中S为所求圆的面积,π为圆周率,r为圆的半径. 示例: # 定义一个方法来计算圆的面积 def findArea(r): PI = 3.142 re ...

  8. python求圆面积_python如何求圆的面积

    首先我们要知道圆的面积计算公式:S = πr²,公式中S为所求圆的面积,π为圆周率,r为圆的半径. 示例: # 定义一个方法来计算圆的面积 def findArea(r): PI = 3.142 re ...

  9. python求圆面积_python如何求圆的面积 python求圆的面积方法

    python如何求圆的面积?本篇文章小编给大家分享一下python求圆的面积方法,代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 首先我们要知道圆的面积计算 ...

最新文章

  1. Servlet,过滤器,监听器,拦截器的区别
  2. 马云口中的“计划经济”其实是一种大数据和人工智能
  3. JavaWeb:HttpServletResponse和HttpServletRequest
  4. win10系统的定位服务器,Win10系统无法开启定位功能的原因及解决方法
  5. linux真实地址是什么意思,linux – 如何为发件人地址配置真实域名
  6. java如何编译运行?
  7. 阿里云,CentOS下yum安装mysql,jdk,tomcat
  8. [转载] python中断响应_用Python脚本监测.py脚本的进程状态,并实现中断重启。
  9. Java中简单Http请求
  10. 深圳端午节骑行活动,欢迎大家参加
  11. Ubuntu上安装gcc
  12. 论文笔记:TABERT: Pretraining for Joint Understanding of Textual and Tabular Data
  13. 新能源汽车车载智能终端t-box
  14. python ansible
  15. Ubuntu 下 LaTeX 图形环境的配置——使用Kile
  16. yolov1原文地址以及论文翻译
  17. 基于微信小程序的每日签到打卡
  18. 做数据分析,连趋势分析法都不会,就白混了!
  19. Layui框架实现图片上传
  20. Linux部署人大金仓(Kingbase8)

热门文章

  1. 在CentOS 6.9 x86_64的OpenResty 1.13.6.1上使用LuaRocks示例
  2. HLS中m3u8格式规范解读
  3. 与后台通讯,首先要了解AMF协议
  4. 在一台电脑上使用两个github账号
  5. await使用中的阻塞和并发(一)
  6. 项目管理中问题与对策探讨
  7. tomcat启动后 项目运行缓慢,要几十到几百秒不等 怎么样./startup.sh 运行加快
  8. SecureCRT中sqlplus,使用Backspace删除时 ^H^H
  9. [冲昏头脑]IDEA中的maven项目中学习log4j的日志操作
  10. 制作显示欢迎信息的脚本程序