179 lines
5.0 KiB
Markdown
179 lines
5.0 KiB
Markdown
---
|
||
doc_type: short
|
||
full_text: sources/03_Debugging.md
|
||
---
|
||
|
||
# 03_Debugging 总结
|
||
|
||
本文讲解 Python 程序崩溃后的基础调试方法,重点包括如何阅读 traceback、使用交互式解释器保留现场、用 `print()` 辅助排查,以及通过 Python 内置调试器 `pdb` 进行断点调试。
|
||
|
||
## 核心内容
|
||
|
||
### 1. 从 traceback 开始定位错误
|
||
|
||
当 Python 程序崩溃时,会输出 traceback,展示函数调用链和最终异常原因。
|
||
|
||
关键原则:
|
||
|
||
- traceback 的最后一行通常是崩溃的直接原因。
|
||
- 上方的 `File ... line ... in ...` 展示了调用栈,即程序如何一步步走到出错位置。
|
||
- 错误类型和错误信息非常重要,例如:
|
||
- `AttributeError: 'int' object has no attribute 'append'`
|
||
- 表示代码试图在整数对象上调用 `append()` 方法。
|
||
|
||
文中建议:如果 traceback 难以理解,可以把完整 traceback 粘贴到搜索引擎中查找相关解释。
|
||
|
||
相关概念:debugging、traceback、exceptions
|
||
|
||
## 2. 使用 `python3 -i` 保留崩溃现场
|
||
|
||
运行脚本时加上 `-i` 选项:
|
||
|
||
```bash
|
||
python3 -i blah.py
|
||
```
|
||
|
||
如果程序崩溃,Python 不会立即退出,而是进入交互式 REPL:
|
||
|
||
```python
|
||
>>>
|
||
```
|
||
|
||
这样可以在崩溃后继续检查解释器状态,例如:
|
||
|
||
- 查看变量值
|
||
- 调用函数
|
||
- 检查对象类型
|
||
- 复现局部问题
|
||
|
||
这种方式适合快速探索程序崩溃时的环境,是一种轻量级调试技巧。
|
||
|
||
相关概念:repl、debugging、runtime state
|
||
|
||
## 3. 使用 `print()` 调试
|
||
|
||
`print()` 调试是一种常见且实用的排查方式,通过在代码中输出变量和执行路径来理解程序行为。
|
||
|
||
本文特别强调:调试输出时应优先使用 `repr()`:
|
||
|
||
```python
|
||
def spam(x):
|
||
print('DEBUG:', repr(x))
|
||
```
|
||
|
||
原因是:
|
||
|
||
- `print(x)` 输出的是面向用户的友好显示。
|
||
- `repr(x)` 输出的是更精确、面向开发者的表示形式。
|
||
|
||
示例:
|
||
|
||
```python
|
||
>>> from decimal import Decimal
|
||
>>> x = Decimal('3.4')
|
||
>>> print(x)
|
||
3.4
|
||
>>> print(repr(x))
|
||
Decimal('3.4')
|
||
```
|
||
|
||
在调试中,`repr()` 能揭示对象的真实类型和构造形式,减少误判。
|
||
|
||
相关概念:print debugging、repr、debugging
|
||
|
||
## 4. 在程序中手动启动调试器
|
||
|
||
Python 3.7+ 可以使用内置函数 `breakpoint()` 在代码中设置调试入口:
|
||
|
||
```python
|
||
def some_function():
|
||
...
|
||
breakpoint()
|
||
...
|
||
```
|
||
|
||
程序执行到 `breakpoint()` 时会进入调试器,可以检查变量、单步执行、查看调用栈等。
|
||
|
||
旧版本 Python 中常见写法是:
|
||
|
||
```python
|
||
import pdb
|
||
pdb.set_trace()
|
||
```
|
||
|
||
`breakpoint()` 是现代推荐写法,而 `pdb.set_trace()` 仍会在旧教程或遗留代码中出现。
|
||
|
||
相关概念:pdb、breakpoints、debugging
|
||
|
||
## 5. 在调试器下运行整个程序
|
||
|
||
可以用 `pdb` 模块直接运行脚本:
|
||
|
||
```bash
|
||
python3 -m pdb someprogram.py
|
||
```
|
||
|
||
这样程序会在第一条语句前进入调试器,允许开发者提前设置断点、配置执行路径,并逐步观察程序运行。
|
||
|
||
常用 `pdb` 命令包括:
|
||
|
||
| 命令 | 作用 |
|
||
|---|---|
|
||
| `help` | 查看帮助 |
|
||
| `w` / `where` | 打印调用栈 |
|
||
| `d` / `down` | 向下移动一个栈帧 |
|
||
| `u` / `up` | 向上移动一个栈帧 |
|
||
| `b loc` / `break loc` | 设置断点 |
|
||
| `s` / `step` | 单步执行 |
|
||
| `c` / `continue` | 继续运行 |
|
||
| `l` / `list` | 列出源码 |
|
||
| `a` / `args` | 查看当前函数参数 |
|
||
| `!statement` | 执行 Python 语句 |
|
||
|
||
断点位置可以是:
|
||
|
||
```text
|
||
b 45 # 当前文件第 45 行
|
||
b file.py:45 # file.py 的第 45 行
|
||
b foo # 当前文件中的 foo() 函数
|
||
b module.foo # 某模块中的 foo() 函数
|
||
```
|
||
|
||
相关概念:pdb、breakpoints、call stack
|
||
|
||
## 练习
|
||
|
||
### Exercise 8.4: Bugs? What Bugs?
|
||
|
||
练习标题以玩笑方式强调:程序“能运行”并不代表没有 bug。调试是理解程序状态、定位异常和验证假设的重要过程。
|
||
|
||
## 关键收获
|
||
|
||
- traceback 是崩溃分析的第一入口,最后一行通常说明直接原因。
|
||
- `python3 -i script.py` 可以在脚本崩溃后保留交互式环境,方便检查状态。
|
||
- `print()` 调试简单有效,但输出调试信息时应优先使用 `repr()`。
|
||
- `breakpoint()` 是 Python 3.7+ 推荐的内置调试入口。
|
||
- `python3 -m pdb program.py` 可以从程序开始就进入调试器。
|
||
- `pdb` 支持调用栈查看、断点、单步执行、继续运行和动态执行语句等功能。
|
||
|
||
## 可延伸概念
|
||
|
||
- debugging:程序调试的一般策略与工具。
|
||
- traceback:Python 异常调用栈的阅读方法。
|
||
- pdb:Python 内置调试器的命令与工作流。
|
||
- repl:交互式解释器在调试中的用途。
|
||
- repr:对象精确表示与调试输出。
|
||
- breakpoints:断点在程序执行控制中的作用。
|
||
|
||
## Related Concepts
|
||
- [[concepts/调用栈与-traceback]]
|
||
- [[concepts/Python-pdb-调试器]]
|
||
- [[concepts/测试-日志与调试]]
|
||
- [[concepts/异常处理]]
|
||
- [[concepts/Python-交互式解释器]]
|
||
- [[concepts/课程练习工作流]]
|
||
- [[concepts/Python-开发环境]]
|
||
- [[concepts/断言]]
|
||
- [[concepts/Python-文档与帮助系统]]
|
||
- [[concepts/库接口设计]]
|