python-debugger
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePython Debugger
Python调试器
Debugging Process
调试流程
- Understand the Error -> 2. Reproduce -> 3. Isolate -> 4. Identify Root Cause -> 5. Fix -> 6. Verify
- 理解错误 -> 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 errorCommon 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 resultspython
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 resultsUsing 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 resultpdb commands: see references/pdb-commands.md
python
import pdb
def problematic_function(x):
pdb.set_trace() # 执行在此处暂停
# 或者使用: breakpoint() # Python 3.7+
result = x * 2
return resultpdb命令:查看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 resultpython
from icecream import ic
def calculate(x, y):
ic(x, y) # 输出: ic| x: 5, y: 0
result = x / y
ic(result)
return resultStep 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. not
int(a) + int(b)a + b - Mutable default arguments: Use then
def f(items=None):insideitems = items or [] - Circular imports: Use lazy imports inside functions:
from .module import Class - Async/await: Missing returns coroutine instead of result
await - Key/Index errors: Use for dicts, check
.get(key, default)for listslen() - Scope issues: /
globaldeclarations, closure variable capture in loopsnonlocal - Encoding: Specify in
encoding="utf-8"callsopen() - Float precision: Use or
decimal.Decimalfor comparisonsmath.isclose() - Resource leaks: Use statements for files, connections, locks
with
- 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 == 5python
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 == 5Debugging 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
undefinedpython
undefinedTime 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():
# ...
undefinedfrom memory_profiler import profile
@profile
def memory_heavy_function():
# ...
undefinedUsing rich for better output
使用rich优化输出
python
from rich.traceback import install
install(show_locals=True) # Enhanced tracebackspython
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
- 晦涩的错误信息
- 库特定的错误
- 版本兼容性问题
- 未文档化的行为