# 调试技巧与断言

URL: https://caijiao.org/python/ch09/debug
Source: docs/python/ch09/debug.md
Description: 本章介绍 Python 中的调试技巧和断言机制，帮助开发者在调试过程中更高效地定位和解决问题。

调试是软件开发过程中不可或缺的一部分。在 [Python](/python/) 中，我们可以通过一些技巧和工具来帮助我们快速定位和解决问题。`assert` 语句是 Python 中的一种调试工具，用于在开发过程中进行条件检查，确保程序运行时某些条件始终为真。

## 使用打印调试

最常见的调试方法是通过打印（`print`）调试信息来查看程序运行过程中的变量值和程序状态。尽管这种方法简单有效，但在大型项目中可能变得冗长和混乱。

```python
def add(a, b):
    print(f"a: {a}, b: {b}")  # 调试信息
    return a + b

result = add(5, 3)
print(f"result: {result}")
```

虽然这种方法可以帮助我们理解程序的运行过程，但它不适用于复杂或大型项目。因此，我们需要更高级的调试技巧。

## 使用调试器（pdb）

Python 提供了内建的调试器 `pdb`，它能够帮助我们在程序运行时单步执行代码、检查变量的值并动态调整程序的行为。

### 启用调试器

在代码中插入 `import pdb; pdb.set_trace()`，程序运行到该语句时会暂停，并进入交互式调试模式。

```python
import pdb

def add(a, b):
    pdb.set_trace()  # 调试中断点
    return a + b

result = add(5, 3)
print(f"result: {result}")
```

进入调试模式后，我们可以执行一些调试命令，如：

- `n`：执行下一行代码
- `s`：进入当前行调用的函数
- `c`：继续执行程序直到下一个断点
- `p <expression>`：打印表达式的值

## 使用日志调试

对于较为复杂的程序，使用日志记录比 `print` 更加有效。Python 的 `logging` 模块提供了灵活的日志记录功能，允许我们设置日志级别、输出到不同的目标等。

```python
import logging

# 设置日志配置
logging.basicConfig(level=logging.DEBUG)

def add(a, b):
    logging.debug(f"a: {a}, b: {b}")
    return a + b

result = add(5, 3)
logging.info(f"result: {result}")
```

`logging` 提供了多种日志级别，帮助我们更好地组织调试信息：

- `DEBUG`：详细的调试信息
- `INFO`：普通的信息
- `WARNING`：警告信息
- `ERROR`：错误信息
- `CRITICAL`：严重错误

## 使用断言（assert）

断言是 Python 中用于调试的一种机制，它能够确保程序的某个条件为真。如果断言条件为假，程序将抛出 `AssertionError` 异常。

```python
def divide(a, b):
    assert b != 0, "除数不能为零"  # 断言条件
    return a / b

result = divide(10, 2)
print(f"result: {result}")
```

如果 `b` 等于 0，程序会抛出异常：

```python
AssertionError: 除数不能为零
```

### 断言与条件表达式

断言通常与条件表达式结合使用，检查函数参数、返回值或其他关键条件是否符合预期。使用断言可以确保程序在开发和测试阶段符合预定的假设和逻辑。

```python
def square_root(x):
    assert x >= 0, "输入值不能为负"
    return x ** 0.5

result = square_root(9)
print(f"result: {result}")
```

## 关闭断言

在生产环境中，我们通常不希望断言检查占用额外的性能。可以通过设置 `PYTHONOPTIMIZE` 环境变量来禁用断言：

```bash
python -O myscript.py
```

这样会关闭所有的断言检查。

## 总结

- 打印调试适用于简单的情况，但对于复杂程序更推荐使用调试器或日志记录。
- `pdb` 是 Python 的内建调试器，能够帮助我们单步执行代码、检查变量等。
- `logging` 模块提供了灵活的日志功能，适用于复杂应用的调试。
- 断言用于条件检查，确保程序在运行过程中满足预期的假设，可以帮助捕捉潜在的错误。
