目录 | 上一节 (8.2 日志) | 下一节 (9 包)

8.3 调试

调试建议

假设程序崩溃了:

  1. bash % python3 blah.py
  2. Traceback (most recent call last):
  3. File "blah.py", line 13, in ?
  4. foo()
  5. File "blah.py", line 10, in foo
  6. bar()
  7. File "blah.py", line 7, in bar
  8. spam()
  9. File "blah.py", 4, in spam
  10. line x.append(3)
  11. AttributeError: 'int' object has no attribute 'append'

那么现在该怎么办呢?

阅读回溯信息

最后一行是程序崩溃的具体原因:

  1. bash % python3 blah.py
  2. Traceback (most recent call last):
  3. File "blah.py", line 13, in ?
  4. foo()
  5. File "blah.py", line 10, in foo
  6. bar()
  7. File "blah.py", line 7, in bar
  8. spam()
  9. File "blah.py", 4, in spam
  10. line x.append(3)
  11. # Cause of the crash
  12. AttributeError: 'int' object has no attribute 'append'

不过,回溯信息并不总是那么易于阅读或理解。

专业建议:将整个回溯粘贴到谷歌。

使用交互式解释器(REPL)

执行脚本的 时候,可以使用选项 -i 使 Python 保持存活(keep alive)。

  1. bash % python3 -i blah.py
  2. Traceback (most recent call last):
  3. File "blah.py", line 13, in ?
  4. foo()
  5. File "blah.py", line 10, in foo
  6. bar()
  7. File "blah.py", line 7, in bar
  8. spam()
  9. File "blah.py", 4, in spam
  10. line x.append(3)
  11. AttributeError: 'int' object has no attribute 'append'
  12. >>>

选项 -i 可以保留解释器状态。这意味着可以在程序崩溃后查找错误信息。对变量的值和其它状态进行检查。

使用打印进行调试

使用 print() 函数进行调试非常常见。

建议:确保使用的是 repr() 函数

  1. def spam(x):
  2. print('DEBUG:', repr(x))
  3. ...

repr() 函数显示一个值的准确表示,而不是格式良好的输出。

  1. >>> from decimal import Decimal
  2. >>> x = Decimal('3.4')
  3. # NO `repr`
  4. >>> print(x)
  5. 3.4
  6. # WITH `repr`
  7. >>> print(repr(x))
  8. Decimal('3.4')
  9. >>>

Python 的调试器

可以在程序内手动启动调试器(debugger)。

  1. def some_function():
  2. ...
  3. breakpoint() # Enter the debugger (Python 3.7+)
  4. ...

上述操作会在 breakpoint() 调用时启动调试器。

在 Python 的早期版本中,可能会看到下面这样的调试指南:

  1. import pdb
  2. ...
  3. pdb.set_trace() # Instead of `breakpoint()`
  4. ...

(译注:Python 3.7 之后,可以使用内置函数 breakpoint() 代替 import pdb; pdb.set_trace()

在调试解释器下运行程序

也可以在调试器下运行整个程序:

  1. bash % python3 -m pdb someprogram.py

上述操作会在第一行语句之前自动进入调试器,允许设置断点和修改配置。

常见的调试器命令:

  1. (Pdb) help # Get help
  2. (Pdb) w(here) # Print stack trace
  3. (Pdb) d(own) # Move down one stack level
  4. (Pdb) u(p) # Move up one stack level
  5. (Pdb) b(reak) loc # Set a breakpoint
  6. (Pdb) s(tep) # Execute one instruction
  7. (Pdb) c(ontinue) # Continue execution
  8. (Pdb) l(ist) # List source code
  9. (Pdb) a(rgs) # Print args of current function
  10. (Pdb) !statement # Execute statement

断点的位置可以用下列任意一种方式进行表示:

  1. (Pdb) b 45 # Line 45 in current file
  2. (Pdb) b file.py:45 # Line 34 in file.py
  3. (Pdb) b foo # Function foo() in current file
  4. (Pdb) b module.foo # Function foo() in a module

练习

练习 8.4:Bugs? 什么是 Bugs?

有 bug,我们就解决 bug(It runs. Ship it!)。

目录 | 上一节 (8.2 日志) | 下一节 (9 包)