为什么Python中的'for'循环会改变未引用的列表?
我正在写一个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
就是指向l
或y
里面某个实际元素的一个引用。如果你改变了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']]