python-debugger

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Debugger

Python调试器

Debugging Process

调试流程

  1. Understand the Error -> 2. Reproduce -> 3. Isolate -> 4. Identify Root Cause -> 5. Fix -> 6. Verify
  1. 理解错误 -> 2. 复现问题 -> 3. 隔离问题 -> 4. 定位根本原因 -> 5. 修复问题 -> 6. 验证修复

Step 1: Understand the Error

步骤1:理解错误

Reading Tracebacks

解读回溯信息

Traceback (most recent call last):        <- Read bottom to top
  File "app.py", line 45, in main         <- Entry point
    result = process_data(data)           <- Call chain
  File "processor.py", line 23, in process_data
    return transform(item)                <- Getting closer
  File "transformer.py", line 12, in transform
    return item["value"] / item["count"]  <- Error location
ZeroDivisionError: division by zero       <- The actual error
Common error types: see references/python-error-types.md
Traceback (most recent call last):        <- 从下往上读
  File "app.py", line 45, in main         <- 入口点
    result = process_data(data)           <- 调用链
  File "processor.py", line 23, in process_data
    return transform(item)                <- 逐步接近错误源
  File "transformer.py", line 12, in transform
    return item["value"] / item["count"]  <- 错误位置
ZeroDivisionError: division by zero       <- 实际错误类型
常见错误类型:查看references/python-error-types.md

Step 2: Reproduce the Issue

步骤2:复现问题

Create a minimal test case that triggers the error. Answer these questions:
  • What input triggered this?
  • Is it consistent or intermittent?
  • When did it start happening?
  • What changed recently?
创建一个能触发错误的最小测试用例。回答以下问题:
  • 是什么输入触发了这个错误?
  • 是持续出现还是间歇性的?
  • 什么时候开始出现的?
  • 最近有什么变更?

Step 3: Isolate the Problem

步骤3:隔离问题

Print Debugging

打印调试法

python
def process_data(data):
    print(f"DEBUG: data type = {type(data)}")
    print(f"DEBUG: data = {data}")

    for i, item in enumerate(data):
        print(f"DEBUG: processing item {i}: {item}")
        result = transform(item)
        print(f"DEBUG: result = {result}")

    return results
python
def process_data(data):
    print(f"DEBUG: data type = {type(data)}")
    print(f"DEBUG: data = {data}")

    for i, item in enumerate(data):
        print(f"DEBUG: processing item {i}: {item}")
        result = transform(item)
        print(f"DEBUG: result = {result}")

    return results

Using pdb

使用pdb调试器

python
import pdb

def problematic_function(x):
    pdb.set_trace()  # Execution stops here
    # Or use: breakpoint()  # Python 3.7+
    result = x * 2
    return result
pdb commands: see references/pdb-commands.md
python
import pdb

def problematic_function(x):
    pdb.set_trace()  # 执行在此处暂停
    # 或者使用: breakpoint()  # Python 3.7+
    result = x * 2
    return result
pdb命令:查看references/pdb-commands.md

Using icecream

使用icecream工具

python
from icecream import ic

def calculate(x, y):
    ic(x, y)  # Prints: ic| x: 5, y: 0
    result = x / y
    ic(result)
    return result
python
from icecream import ic

def calculate(x, y):
    ic(x, y)  # 输出: ic| x: 5, y: 0
    result = x / y
    ic(result)
    return result

Step 4: Common Root Causes

步骤4:常见根本原因

  • None values: Check return values before accessing attributes. Guard with
    if x is None: raise ValueError(...)
  • Type mismatches: Add type hints, cast inputs explicitly.
    int(a) + int(b)
    not
    a + b
  • Mutable default arguments: Use
    def f(items=None):
    then
    items = items or []
    inside
  • Circular imports: Use lazy imports inside functions:
    from .module import Class
  • Async/await: Missing
    await
    returns coroutine instead of result
  • Key/Index errors: Use
    .get(key, default)
    for dicts, check
    len()
    for lists
  • Scope issues:
    global
    /
    nonlocal
    declarations, closure variable capture in loops
  • Encoding: Specify
    encoding="utf-8"
    in
    open()
    calls
  • Float precision: Use
    decimal.Decimal
    or
    math.isclose()
    for comparisons
  • Resource leaks: Use
    with
    statements for files, connections, locks
  • None值:在访问属性前检查返回值。使用
    if x is None: raise ValueError(...)
    做防护
  • 类型不匹配:添加类型提示,显式转换输入。使用
    int(a) + int(b)
    而非
    a + b
  • 可变默认参数:使用
    def f(items=None):
    ,然后在函数内设置
    items = items or []
  • 循环导入:在函数内部使用延迟导入:
    from .module import Class
  • Async/await问题:缺少
    await
    会返回协程对象而非结果
  • 键/索引错误:对字典使用
    .get(key, default)
    ,对列表检查
    len()
  • 作用域问题
    global
    /
    nonlocal
    声明,循环中的闭包变量捕获
  • 编码问题:在
    open()
    调用中指定
    encoding="utf-8"
  • 浮点数精度问题:使用
    decimal.Decimal
    math.isclose()
    进行比较
  • 资源泄漏:对文件、连接、锁使用
    with
    语句

Step 5: Fix Patterns

步骤5:修复模式

Defensive Programming

防御性编程

python
def safe_divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

def safe_get(data: dict, key: str, default=None):
    return data.get(key, default)
python
def safe_divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

def safe_get(data: dict, key: str, default=None):
    return data.get(key, default)

Input Validation

输入验证

python
def process_user(user_id: int, data: dict) -> dict:
    if not isinstance(user_id, int) or user_id <= 0:
        raise ValueError(f"Invalid user_id: {user_id}")

    required_fields = ["name", "email"]
    missing = [f for f in required_fields if f not in data]
    if missing:
        raise ValueError(f"Missing required fields: {missing}")
python
def process_user(user_id: int, data: dict) -> dict:
    if not isinstance(user_id, int) or user_id <= 0:
        raise ValueError(f"Invalid user_id: {user_id}")

    required_fields = ["name", "email"]
    missing = [f for f in required_fields if f not in data]
    if missing:
        raise ValueError(f"Missing required fields: {missing}")

Exception Handling

异常处理

python
import logging

logger = logging.getLogger(__name__)

def fetch_user_data(user_id: int) -> dict:
    try:
        response = api_client.get(f"/users/{user_id}")
        response.raise_for_status()
        return response.json()
    except requests.HTTPError as e:
        logger.error(f"HTTP error fetching user {user_id}: {e}")
        raise
    except requests.ConnectionError:
        logger.error(f"Connection failed for user {user_id}")
        raise ServiceUnavailableError("API unavailable")
python
import logging

logger = logging.getLogger(__name__)

def fetch_user_data(user_id: int) -> dict:
    try:
        response = api_client.get(f"/users/{user_id}")
        response.raise_for_status()
        return response.json()
    except requests.HTTPError as e:
        logger.error(f"HTTP error fetching user {user_id}: {e}")
        raise
    except requests.ConnectionError:
        logger.error(f"Connection failed for user {user_id}")
        raise ServiceUnavailableError("API unavailable")

Step 6: Verify the Fix

步骤6:验证修复效果

python
import pytest

def test_transform_handles_zero_count():
    """Verify fix for ZeroDivisionError."""
    data = {"value": 10, "count": 0}

    with pytest.raises(ValueError, match="count cannot be zero"):
        transform(data)

def test_transform_normal_case():
    """Verify normal operation still works."""
    data = {"value": 10, "count": 2}
    result = transform(data)
    assert result == 5
python
import pytest

def test_transform_handles_zero_count():
    """验证ZeroDivisionError的修复效果。"""
    data = {"value": 10, "count": 0}

    with pytest.raises(ValueError, match="count cannot be zero"):
        transform(data)

def test_transform_normal_case():
    """验证正常场景下仍能正常工作。"""
    data = {"value": 10, "count": 2}
    result = transform(data)
    assert result == 5

Debugging Tools

调试工具

Logging Setup

日志配置

python
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(name)s %(levelname)s: %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler(),
    ],
)
python
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(name)s %(levelname)s: %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler(),
    ],
)

Profiling

性能分析

python
undefined
python
undefined

Time profiling

时间性能分析

import cProfile cProfile.run("main()", "output.prof")
import cProfile cProfile.run("main()", "output.prof")

Memory profiling

内存性能分析

from memory_profiler import profile
@profile def memory_heavy_function(): # ...
undefined
from memory_profiler import profile
@profile def memory_heavy_function(): # ...
undefined

Using rich for better output

使用rich优化输出

python
from rich.traceback import install
install(show_locals=True)  # Enhanced tracebacks
python
from rich.traceback import install
install(show_locals=True)  # 增强版回溯信息

References

参考资料

  • Debug Checklist
  • Common Error Types
  • pdb Commands
  • 调试检查清单
  • 常见错误类型
  • pdb命令参考

When to Use WebSearch

何时使用网络搜索

  • Cryptic error messages
  • Library-specific errors
  • Version compatibility issues
  • Undocumented behavior
  • 晦涩的错误信息
  • 库特定的错误
  • 版本兼容性问题
  • 未文档化的行为