python基础-11-调试程序
文章目录
- 【README】
- 【11】调试
- 【11.1】抛出异常
- 【11.1.1】抛出异常代码块
- 【11.2】获取回溯字符串
- 【11.2.1】traceback获取异常回溯信息
- 【11.3】断言
- 【11.3.1】断言代码示例
- 【11.4】日志(使用logging模块)
- 【11.4.1】使用logging模块操作日志
- 【11.4.3】日志级别(按照消息重要性对日志分类)
- 【11.4.4】禁用日志
- 【11.4.5】把日志记录到文件
- 【11.5】调试程序(调试器模式)
- 【11.6】小结
【README】
本文总结自《python编程快速上手-让繁琐工作自动化》第11章,非常棒的一本书,墙裂推荐;
【11】调试
【11.1】抛出异常
1)回顾捕获异常代码示例(try-exception代码块):
# 异常处理
print('\n=== 异常处理 ===')
def handleExp(operator):
try:
return 42 / operator
except ZeroDivisionError:
print(str(operator) + ', 导致0除异常')
return None
print(handleExp(1))
print(handleExp(2))
# 0除异常
print(handleExp(0))
print(handleExp(3))
【11.1.1】抛出异常代码块
1)抛出异常代码:
- 使用raise关键字;
- 对Exception函数调用;
- 传递给Exception函数字符串,包含错误信息;
# 定义函数,抛出异常
def callPhone(phoneNumber):
if phoneNumber == '110':
raise Exception("110不是合法电话号码")
elif phoneNumber == '120':
raise Exception("120不是合法电话号码")
print('Calling Phone Number:', phoneNumber)
def iphone(phoneNumber):
try:
callPhone(phoneNumber)
except Exception as error:
print("exception happened: " + str(error))
# 调用函数
iphone("110")
iphone("120")
iphone("130")
# exception happened: 110不是合法电话号码
# exception happened: 120不是合法电话号码
# Calling Phone Number: 130
【11.2】获取回溯字符串
1)异常的回溯字符串包括:错误信息, 导致该错误的代码行号,以及导致该错误的函数调用的序列,这个序列称为调用栈;
# 11.2 获取回溯字符串
def dinner():
bacon()
def bacon():
raise Exception('this is the error msg.')
# 调用函数,打印异常的回溯信息
dinner()
# Traceback (most recent call last):
# File "D:\studynote\00-ai-llm\workbench\PythonBasicStudy\chapter11\1102.py", line 9, in <module>
# dinner()
# File "D:\studynote\00-ai-llm\workbench\PythonBasicStudy\chapter11\1102.py", line 4, in dinner
# bacon()
# File "D:\studynote\00-ai-llm\workbench\PythonBasicStudy\chapter11\1102.py", line 6, in bacon
# raise Exception('this is the error msg.')
# Exception: this is the error msg.
【11.2.1】traceback获取异常回溯信息
1)引入 traceback模块;
import traceback
from pathlib import Path
def dinnerWithTraceBack():
try:
dinner()
except:
errorFile = open(Path.cwd() / 'errorInfo.txt', 'w')
# 把异常的回溯信息写入文件
errorFile.write(traceback.format_exc())
errorFile.close()
print('the traceback info was written to errorInfo.txt')
# 调用函数,使用traceback收集异常信息
dinnerWithTraceBack()
【补充】写入文件errorInfo.txt的内容就是11.2 Traceback (most recent call last): 打印出的异常栈内容;
【11.3】断言
1)断言:是健全性检查,用于确保代码没有做什么明显错误的事情;
- 断言检查由assert语句执行; 若检查失败,会抛出异常;
2)在代码中, assert包含如何部分:
- assert关键字;
- 条件(求值为True或False的表达式)
- 逗号
- 当条件为False显示的字符串;
3)断言与异常不同,异常可以按需捕获;而断言不应该被try-except代码块捕获,如果assert失败,程序就应该崩溃 ;
- 断言针对的是程序员的错误,而不是用户错误;
- 断言只能在程序开发时失败,用户永远都不会在完成的程序中看到断言错误;
- 对于正常运行中的错误,不应该使用assert来检测它;不应该用assert来引发异常,因为用户可以选择关闭断言;
【11.3.1】断言代码示例
# 定义函数,使用断言做判断
# (在生产环境中不要参考该代码,仅做测试,因为运行时的程序不应该使用断言,而在程序或应用启动时可以使用)
def callPhoneWithAssert(phoneNumber):
assert len(phoneNumber) == 11, phoneNumber + 'is not a valid phone number'
print('Calling Phone Number:', phoneNumber)
# 调用函数
callPhoneWithAssert('110')
【断言结果】
Traceback (most recent call last):
File "D:\studynote\00-ai-llm\workbench\PythonBasicStudy\chapter11\1103.py", line 8, in <module>
callPhoneWithAssert('110')
File "D:\studynote\00-ai-llm\workbench\PythonBasicStudy\chapter11\1103.py", line 4, in callPhoneWithAssert
assert len(phoneNumber) == 11, phoneNumber + 'is not a valid phone number'
^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 110is not a valid phone number
【11.4】日志(使用logging模块)
【11.4.1】使用logging模块操作日志
1)使用logging模块打印日志
import logging
# 设置日志格式
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
def callPhoneWithLogging(phoneNumber):
logging.debug('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.info('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.warning('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.error('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.critical('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
if (len(phoneNumber) != 11):
logging.error('%s is not a valid phone number', phoneNumber)
print('Calling Phone Number:', phoneNumber)
# 调用函数,打印日志
callPhoneWithLogging('110')
【打印结果】
2025-04-05 07:07:03 - root - DEBUG - calling callPhoneWithLogging() , phoneNumber:110
2025-04-05 07:07:03 - root - INFO - calling callPhoneWithLogging() , phoneNumber:110
2025-04-05 07:07:03 - root - WARNING - calling callPhoneWithLogging() , phoneNumber:110
2025-04-05 07:07:03 - root - ERROR - calling callPhoneWithLogging() , phoneNumber:110
2025-04-05 07:07:03 - root - CRITICAL - calling callPhoneWithLogging() , phoneNumber:110
2025-04-05 07:07:03 - root - ERROR - 110 is not a valid phone number
Calling Phone Number: 110
【11.4.3】日志级别(按照消息重要性对日志分类)
1)5个日志级别,从最不重要到最重要;利用不同日志函数,消息可以按照某个级别记入日志;
2)日志重要性从低到高:
- DEBUG;
- INFO
- WARNING
- ERROR
- CRITICAL
【11.4.4】禁用日志
1)调用logging.disable(level):禁止该级别和更低级别的所有日志消息;
- 如果想要禁用所有日志,可以调用logging.disable(CRITICAL)
2)禁用 ERROR及以下日志的写法:
import logging
# 设置日志格式
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
# 禁用 ERROR 及以下日志的写法
logging.disable(logging.ERROR)
def callPhoneWithLogging(phoneNumber):
logging.debug('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.info('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.warning('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.error('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
logging.critical('calling callPhoneWithLogging() , phoneNumber:%s', phoneNumber)
if (len(phoneNumber) != 11):
logging.error('%s is not a valid phone number', phoneNumber)
print('Calling Phone Number:', phoneNumber)
# 调用函数,打印日志
callPhoneWithLogging('110')
【打印结果】
Calling Phone Number: 110
2025-04-05 07:08:38 - root - CRITICAL - calling callPhoneWithLogging() , phoneNumber:110
【11.4.5】把日志记录到文件
logging.basicConfig(filename="diyLog.txt", level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
【11.5】调试程序(调试器模式)
1)调试模式的按钮:
- continue:程序执行到终点或下一个断点;
- step In:执行到下一行代码,然后再次暂停; 如果下一行代码是函数调用,则进入到函数并跳转到函数的第一行代码;
- step over:执行到下一行代码, 若下一行代码是函数调用,则跳过;
- step out:跳出当前函数调用;
- stop:终止调试;
【11.6】小结
1)断言,异常,日志和调试器都是在程序中发现和预防bug的有效工具;
- 断言:assert
- 异常:try-except代码块去捕获
- 日志:logging