Python 常见 Bug 合集 — 高频陷阱与修复
🔴 高频 + 高难度
1. 可变默认参数
频率: ⭐⭐⭐⭐⭐ 难度: ⭐⭐
# ❌ 默认参数在函数定义时求值,所有调用共享同一对象
def append_to(item, lst=[]):
lst.append(item)
return lst
append_to(1) # [1]
append_to(2) # [1, 2] ← 不是 [2]!
append_to(3) # [1, 2, 3]
# ✅
def append_to(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
2. 浅拷贝陷阱
频率: ⭐⭐⭐⭐ 难度: ⭐⭐⭐
# 列表的 * 运算复制的是引用
grid = [[0] * 3] * 3 # ❌ 三行指向同一个列表!
grid[0][0] = 1
print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
# ✅ 列表推导式
grid = [[0] * 3 for _ in range(3)]
# 字典嵌套同理
import copy
deep = copy.deepcopy(original) # 深拷贝
shallow = original.copy() # 浅拷贝(嵌套对象还是引用)
3. asyncio 中混用同步阻塞调用
频率: ⭐⭐⭐⭐ 难度: ⭐⭐⭐⭐
# ❌ 在 async 函数中调用阻塞函数 → 整个事件循环冻结
async def handler():
data = requests.get("http://api") # requests 是同步库!
time.sleep(1) # time.sleep 也是阻塞的
return data
# ✅
import aiohttp
async def handler():
async with aiohttp.ClientSession() as s:
async with s.get("http://api") as resp:
return await resp.json() # 异步等待,不阻塞
# 必须调同步代码时 → 线程池
result = await asyncio.to_thread(sync_function, arg)
4. GIL 导致多线程无效
频率: ⭐⭐⭐⭐ 难度: ⭐⭐⭐
# ❌ 多线程计算 → GIL 导致串行,反而更慢
import threading
def compute():
for _ in range(10**7): pass
# ✅ CPU 密集型用 multiprocessing
from multiprocessing import Pool
with Pool(4) as p:
results = p.map(compute, range(4))
# ✅ IO 密集型用线程(IO 时会释放 GIL)
# 或者用 asyncio 协程
🟡 中频 + 中难度
5. import 循环依赖
# a.py
from b import func_b
def func_a(): return func_b()
# b.py
from a import func_a # ❌ 循环 import → ImportError
def func_b(): return func_a()
# ✅ 延迟导入
def func_b():
from a import func_a # 在函数内导入
return func_a()
# 或重构:把共同依赖提取到 c.py
6. 闭包变量绑定
# ❌ 所有 lambda 捕获的是同一个变量 i
funcs = []
for i in range(5):
funcs.append(lambda: i) # 延迟绑定,i 最终都是 4
print([f() for f in funcs]) # [4, 4, 4, 4, 4]
# ✅ 默认参数在定义时求值
funcs = [lambda i=i: i for i in range(5)]
print([f() for f in funcs]) # [0, 1, 2, 3, 4]
7. Unicode / 编码问题
# ❌ Windows 默认编码可能不是 UTF-8
with open("file.txt", "r") as f: # 默认用系统编码
text = f.read()
# ✅ 始终显式指定编码
with open("file.txt", "r", encoding="utf-8") as f:
text = f.read()
# ❌ 打印中文在某些终端乱码
print("中文") # 可能输出乱码
# 检查: sys.stdout.encoding
# 设置: PYTHONIOENCODING=utf-8
# ❌ JSON 中文被转义成 \uXXXX
json.dumps({"msg": "你好"}) # '{"msg": "\\u4f60\\u597d"}'
json.dumps({"msg": "你好"}, ensure_ascii=False) # '{"msg": "你好"}'
8. is vs ==
a = [1, 2, 3]
b = [1, 2, 3]
a == b # True — 值相等
a is b # False — 不是同一对象
# ⚠️ 小整数和短字符串被 Python 缓存
x = 256; y = 256; x is y # True(缓存)
x = 257; y = 257; x is y # False(不缓存)
# ✅ 永远用 == 比较值,is 只用于 None/True/False
if x is None: ...
if x is not None: ...
🟢 低频 + 低难度
9. 修改遍历中的列表
# ❌ 遍历中删除元素 → 跳过元素
items = [1, 2, 3, 4, 5]
for item in items:
if item % 2 == 0:
items.remove(item)
print(items) # [1, 3, 5] — 看起来对但逻辑有问题(跳过元素)
# ✅ 列表推导式
items = [item for item in items if item % 2 != 0]
# 或遍历副本
for item in items[:]: # 切片创建副本
if item % 2 == 0:
items.remove(item)
10. 文件未关闭
# ❌ 异常时 f 可能没关闭
f = open("file.txt")
data = f.read()
f.close()
# ✅ with 语句保证关闭
with open("file.txt") as f:
data = f.read()
# 不用手动 close,异常也能正确关闭
11. pip 依赖冲突
# ❌ 全局安装 → 项目间冲突
pip install requests
pip install flask
# ✅ 虚拟环境
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
pip install requests flask
# 锁版本
pip freeze > requirements.txt
# 团队用 requirements.txt 安装
pip install -r requirements.txt
12. Timestamp / 时区混淆
# ❌ naive datetime vs aware datetime 混用 → 5 小时偏移
from datetime import datetime
naive = datetime.now() # 无时区
aware = datetime.now(timezone.utc) # UTC
# naive == aware → TypeError
# ✅ 统一使用时区
from datetime import datetime, timezone, timedelta
utc = datetime.now(timezone.utc)
cst = utc.astimezone(timezone(timedelta(hours=8))) # 北京时间