输入关键词开始搜索

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)))  # 北京时间