python可变对象陷阱有三:一是默认参数用列表/字典会累积,应改用none+内部初始化;二是赋值=引用非复制,需copy()或deepcopy();三是遍历时增删元素会索引错乱,应改用推导式或反向遍历。

Python里列表和字典这类可变对象,用起来方便,但稍不注意就会掉进“共享引用”和“默认参数累积”的坑里。问题不在语法错,而在行为反直觉——表面看是新建、赋值或传参,实际却指向同一块内存,导致修改一处、处处生效。
函数默认参数用列表或字典会累积
这是最经典也最高频的陷阱。默认值不是每次调用都新建,而是在函数定义时初始化一次,之后所有未传参的调用共用同一个对象。
- 错误写法:
def add(x, lst=[]): lst.append(x); return lst→ 第二次调用会带着第一次的元素 - 正确写法:
def add(x, lst=None): if lst is None: lst = []; lst.append(x); return lst - 字典、集合同理:默认值统一用
None,内部判空再初始化
赋值=引用,不是复制
写m = o(其中o是列表或字典),只是让m指向o所指的对象,二者操作的是同一份数据。
- 常见翻车场景:循环中反复修改同一个字典并
append进列表,结果列表里全是最终状态的重复引用 - 修复方式:
m = o.copy()(浅拷贝)或import copy; m = copy.deepcopy(o)(深拷贝) - 注意:
list(o)、dict(o)、o[:]也能实现浅拷贝,但语义不如.copy()清晰
嵌套可变对象修改会穿透原结构
浅拷贝只复制顶层,如果列表里存的是字典,改字典里的键值,原列表里的字典照样被改。
立即学习“Python免费学习笔记(深入)”;
- 例如:
original = [[1], [2]]; copied = original.copy(); copied[0].append(99)→original也变成[[1, 99], [2]] - 需要真正隔离时,必须用
copy.deepcopy() - 简单结构可手动重建:
copied = [item[:] for item in original](适用于二维列表)
遍历时直接增删列表元素会跳项或死循环
for循环按索引顺序走,中间插入或删除会打乱索引节奏,轻则漏处理,重则无限循环。
- 错误示例:
for x in mylist: if x == 'sock': mylist.append('sock')→ 可能一直追加停不下来 - 安全做法:用列表推导式生成新列表,或先收集要删/加的索引,循环结束后统一操作
- 更稳妥:改用
while配合pop(0)或反向遍历for i in range(len(lst)-1, -1, -1)







