Logo

郎哥编程

调试Python程序

2020-12-23 185

程序编写完成或在编写过程中,需要对程序进行测试,根据测试发现的错误,进一步诊断,找出发生错误的原因和具体代码位置进行修改,这个过程称为程序调试。在一些情况下,可能需要查看或跟踪程序的运行状态,这种情况也属于程序调试。

在Python中,程序调试有多种方式可以使用:可以使用print函数在怀疑出错的代码位置输出调试信息,例如输出变量的内容等;也可以使用assert语句(断言语句)输出调试信息;还可以将调试信息输出到log文件,通过log文件了解程序的运行状况,定位发生错误的代码位置;还可以在代码中设置断点,跟踪程序的运行状态,定位发生错误的代码位置。

使用print函数调试程序

使用print函数调试程序,是最容易掌握,也最方便使用的一种程序调试方法。

在怀疑出错的代码位置,使用print函数输出调试信息,根据输出的调试信息来发现错误原因,或查看程序的运行状态。

案例1:查看程序的运行状态

# 定义计算X平方的函数
def squre(x):
    x = x ** 2
    # 输出调试信息,了解程序运行状况
    print(x)
    return x
s = [1,2,3,4,5,6]
# 使用map函数计算列表s所有项的平方
a = map(squre,s)
print(list(a))

案例2:发现程序出现异常的原因

# 定义两数相除函数

def div(a,b):
    # 输出a、b的值,发现发生异常的原因
    print("a=%d:b=%d" % (a,b))
    temp = a / b
    return temp
 
if __name__ == '__main__':
 
    a = int(input("请输入一个整数:"))
    b = int(input("请输入一个整数:"))
    print(div(a,b))

案例2代码使用print函数输出a和b的值,当程序发生异常时,可以查看a和b的值,找到程序发生异常的原因。在案例2中,当b为0就会发生程序异常。

案例2语句“if  __name__ == '__main__'”,用于表示该模块为直接执行模块,也可以说是主模块,只有该模块为主模块时,才会执行if内的语句。

使用assert断言语句调试程序

assert语句允许开发者在程序代码插入调试性断言,assert语句用于判断一个表达式,该表达式返回布尔值,若表达式返回False,则触发AssertionError异常,程序终止。

assert语句的语法如下:

assert expression [, expression]

其中assert是Python关键字,expression是Python表达式,该表达式返回布尔值,在assert关键字后面可以有多个表达式,每个表达式用英文逗号分隔。

案例3:使用assert断言语句调试程序

# 定义两数相除函数
def div(a,b):
    # 使用assert语句断言b不为0
    assert b != 0
    temp = a / b
    return temp
if __name__ == '__main__':
    a = int(input("请输入一个整数:"))
    b = int(input("请输入一个整数:"))
    print(div(a,b))

在程序执行过程中,若b=0,当程序执行到assert b != 0语句时,表达式b != 0返回False,assert语句触发AssertionError异常,程序停止执行。

下面是程序的执行过程:

请输入一个整数:10
请输入一个整数:0
Traceback (most recent call last):
  File "D:/pythoncode/test2.py", line 12, in <module>
    print(div(a,b))
  File "D:/pythoncode/test2.py", line 4, in div
    assert b != 0
AssertionError
>>>

使用log输出程序运行状态

log也称为记录程序运行的日志,通过log把一些可能出现问题的变量、执行的语句状态、重要的节点信息输出到Shell窗口或写到文件中,当程序在运行过程中出现问题时,就可以从输出的信息中跟踪程序的运行信息,及时发现程序存在的问题。

Python提供了日志模块logging,使用该模块可以输出程序调试信息,logging模块的详细使用方法会在后面的课程介绍。

案例4:输出程序运行日志

# 导入logging模块
import logging
# 设置日志输出级别
logging.basicConfig(level=logging.INFO)
# 定义两数相除函数
def div(a,b):
    # 输出日志信息
    logging.info("assert断言:assert b != 0 ")
    assert b != 0
    temp = a / b
    return temp
if __name__ == '__main__':
    a = int(input("请输入一个整数:"))
    # 输出日志信息
    logging.info('a = %d' % a)
    b = int(input("请输入一个整数:"))
    # 输出日志信息
    logging.info('b = %d' % b)
    print(div(a,b))

在程序执行过程中,logging会在指定的位置输出程序运行信息。前缀为INFO的文本行就是logging输出的信息。

请输入一个整数:10
INFO:root:a = 10
请输入一个整数:0
INFO:root:b = 0
INFO:root:assert断言:assert b != 0
Traceback (most recent call last):
  File "D:/pythoncode/test2.py", line 23, in <module>
    print(div(a,b))
  File "D:/pythoncode/test2.py", line 11, in div
    assert b != 0
AssertionError

使用内置函数breakpoint设置断点

内置函数breakpoint可以在任意程序代码行设置断点,当程序运行到断点时会进入pdb调试器。

breakpoint的函数声明:

breakpoint(*args, **kws)

breakpoint是在Python3.7版本新增加的函数,该函数可以方便地在在任意程序代码设置断点,而不需要导入pdb调试模块。该函数最终会调用pdb模块的set_trace()方法,set_trace()方法并没有参数传入,因此调用breakpoint函数设置断点时,可以忽略参数。

当程序运行到breakpoint函数所在的代码行时,会进入pdb调试器运行。

在pdb调试器状态下:

(1)   输入命令“n”,可以单步执行代码,不会进入函数内部;

(2) 输入命令“s”,可以进入函数内部单步执行;

(3)输入命令“p”,可以查看变量内容,在命令“p”后面空格后写入要查看的变量名称,例如 p num;

(4)输入命令“c”,继续运行程序,

(5)输入命令“q”,结束调试。

案例5:设置断点,跟踪程序

# 定义两数相除函数
def div(a,b):
    # 调用breakpoint()函数设置断点
    breakpoint()
    temp = a / b
    return temp
if __name__ == '__main__':
    a = int(input("请输入一个整数:"))
    b = int(input("请输入一个整数:"))
    print(div(a,b))

程序跟踪过程如下:

请输入一个整数:10
请输入一个整数:6
> d:\pythoncode\test2.py(5)div()
-> temp = a / b
(Pdb) p a
10
(Pdb) p b
6
(Pdb) n
> d:\pythoncode\test2.py(6)div()
-> return temp
(Pdb) p temp
1.6666666666666667
(Pdb) n
--Return--
> d:\pythoncode\test2.py(6)div()->1.6666666666666667
-> return temp
(Pdb) n
--Call--
> c:\python\lib\idlelib\run.py(433)write()
-> def write(self, s):
(Pdb) c
1.6666666666666667
>>>

 

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论