迭代列表时如何修改元素?两种场景差异及原因解析
为什么Python迭代列表时修改元素的行为不一致?
先明确两个案例的现象:
- 案例一中,迭代整数列表执行
l += 1后,原列表内容无变化,输出仍为[0, 1, 2, 3, 4] - 案例二中,迭代类实例列表调用
set_n方法后,所有实例的属性都被修改,输出为[4, 4, 4, 4, 4]
核心差异与背后原因
1. 数据类型的可变性差异
Python中的数据类型分为不可变类型(如整数、字符串、元组)和可变类型(如列表、字典、自定义类实例),这是两种行为差异的根本原因:
案例一:不可变类型的特性
整数属于不可变类型,执行l += 1时:
- 迭代过程中,
l是列表中整数元素的引用拷贝 - 因为整数不可变,
l += 1并不是修改原整数对象,而是创建了一个值为原数+1的新整数对象 - 此时
l指向新对象,但原列表中的元素仍指向原来的整数对象,所以原列表内容不会改变
案例二:可变类型的特性
自定义类的实例属于可变类型,调用l.set_n(4)时:
- 迭代过程中,
l是列表中实例对象的引用拷贝,但这个引用和列表中存储的引用指向同一个实例对象 set_n方法直接修改该实例对象内部的self.n属性,没有创建新实例- 原列表中存储的引用仍指向被修改的实例,因此遍历列表时能看到属性变化
2. 额外说明:[Foo(3)] * 5的特性
案例二中list_2 = [Foo(3)] * 5会创建包含5个相同实例引用的列表——这5个元素其实指向同一个Foo实例。所以调用任意一个元素的set_n方法,都会修改这个唯一的实例,最终所有元素的n属性都会变成4,这是可变类型引用复用的特性,和迭代修改的逻辑相辅相成。
示例代码
# 案例一:修改整数列表 list_1 = [0, 1, 2, 3, 4] for l in list_1: l += 1 print(list_1) # 输出: [0, 1, 2, 3, 4] # 案例二:修改类实例列表 class Foo: def __init__(self, n): self.n = n def set_n(self, n): self.n = n list_2 = [Foo(3)] * 5 for l in list_2: l.set_n(4) print([l.n for l in list_2]) # 输出: [4, 4, 4, 4, 4]
内容的提问来源于stack exchange,提问作者G. Gare
相关产品推荐
相关产品推荐

