为什么Python中的'for'循环会改变未引用的列表?

3 投票
3 回答
2333 浏览
提问于 2025-04-16 08:36

我正在写一个Python脚本,这个脚本会从一个CSV文件中读取行,处理这些行,然后再输出。到目前为止,我已经实现了将CSV转换成列表的功能。

我遇到的问题是,当我遍历临时列表时,for循环会改变所有的临时列表,而不仅仅是我想要的那个。下面是我想表达的一个简单例子。

>>> l = [['hi', 'ho'],['no', 'go']]
>>> t = []
>>> y = []
>>> 
>>> for row in l:
...     row[0] = '123'
...     y.append(row)
...     t.append(row)
... 
>>> y
[['123', 'ho'], ['123', 'go']]
>>> t
[['123', 'ho'], ['123', 'go']]

上面的例子应该很简单明了。(假设我想做的不仅仅是复制列表l,只是想保持简单)。

但现在我不明白的部分来了。

>>> z = []
>>> for row in y:
...     row[0] = 'xxxx'
...     z.append(row)
... 
>>> z
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> t
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> y
[['xxxx', 'ho'], ['xxxx', 'go']]

当我想修改子列表中的第一部分,并把它保存到一个新的列表'z'时,它也会修改列表t!

这是怎么回事呢? z、y和t是不是指向同一个内存位置?

还有,这里发生了什么呢?:

>>> for rowx in y:
...     rowx[0] = 'x55x'
...     z.append(rowx)
... 
>>> z
[['xxxx', 'ho'], ['x55x', 'go'], ['x55x', 'go'], ['x55x', 'go']]
>>> t
[['xxxx', 'ho'], ['x55x', 'go']]
>>> y
[['xxxx', 'ho'], ['x55x', 'go']]

和上面的问题类似,为什么y和t也会被改变?

提前谢谢你们!!

3 个回答

0

“z、y 和 t 是指向同一个内存位置吗?”

不是的,但 z[0]、y[0] 和 t[0] 是指向同一个东西(不过别叫它内存位置,这不是 C 语言)。你把同一个列表 ['hi', 'ho'] 添加到了 z、y 和 t 中。所以它们指向的是同一个列表。如果你不想让它们指向同一个列表,你需要先复制一份。

7

在Python中,所有的东西其实都是“引用”。比如说,row就是指向ly里面某个实际元素的一个引用。如果你改变了row的内容,那就意味着你改变了它所指向的那个元素。而如果你把row放到另一个对象里,那其实是把原来的那个元素也放了进去。

4

你的三个列表是不同的,但它们之间只有两个元素是共享的:

>>> y[0] is t[0] is z[0]
True
>>> y[1] is t[1] is z[1]
True

如果 is 操作符告诉你这些引用指向的是同一个对象,那么无论你用哪个引用去修改这个对象,变化都会显现出来。

为了避免这种情况,如果你想要元素的一个副本,可以使用 copy 模块:

>>> import copy
>>> a = copy.deepcopy(y)
>>> a
[['xxxx', 'ho'], ['xxxx', 'go']]
>>> a[0] is y[0]
False
>>> a[0][0] = 'copy!'
>>> y
[['xxxx', 'ho'], ['xxxx', 'go']]

撰写回答