OMG,记录我掉进的一个 Python 的巨简单的坑,并求教怎么爬出来?

2017-10-24 11:26:09 +08:00
 northisland
In[]: a = [[0, 0]]*3
In[]: a
Out[]: [[0, 0],
        [0, 0],
        [0, 0]]
In[]: a[1][1]=3
In[]: a
Out[]: [[0, 3],
        [0, 3],
        [0, 3]]

我只想改[1, 1]的元素,我该怎么改这个代码呢? 列表这个东东,至今我没有吃透。。。

我能想到的是,这种数组来生成

a = numpy.zeros(shape=(10, 3), dtype=int).tolist()

提前谢过各位的指教和观看

2032 次点击
所在节点    问与答
7 条回复
zfz
2017-10-24 11:58:04 +08:00
In [1]: a = [[0, 0] for i in range(3)]

In [2]: a
Out[2]: [[0, 0], [0, 0], [0, 0]]

In [3]: a[1][1] = 3

In [4]: a
Out[4]: [[0, 0], [0, 3], [0, 0]]

In [5]: id(a)
Out[5]: 4490425912

In [6]: id(a[0])
Out[6]: 4486759560

In [7]: id(a[1])
Out[7]: 4490542472 #与 a[0]地址不同

In [8]: b = [[0, 0]] * 3

In [9]: id(b[0])
Out[9]: 4490539808

In [10]: id(b[1])
Out[10]: 4490539808 # 与 b[0]相同


这个情况有趣,以前也没发现。不用*,用列表生成式可以满足。应该是用*生成列表的时候,引用了相同的对象,所以你改动这个对象,导致整个列表都变。这个估计要看 CPython 具体实现。
coderluan
2017-10-24 12:00:14 +08:00
coderluan
2017-10-24 12:03:09 +08:00
简单来说 *3 是浅拷贝,创建二维数组请用 in range
gamexg
2017-10-24 12:10:13 +08:00
列表是引用,那三个实际使指向同一对象。
这样 for 下可以复制列表。

a[i]=a[i][:]
或者
a[i]=[v for v in a[i]]
jedihy
2017-10-24 14:29:52 +08:00
慎用*号开辟数组,原因上面已经说了,浅拷贝。
xiadd
2017-10-24 14:39:34 +08:00
就是引用类型 指向同一个地址, 改变其中一个,三个都会发生变化
scusjs
2017-10-24 15:02:16 +08:00
哈哈遥想起本科刚刚学 Python 时候被这个坑哭,原因上面讲了,浅拷贝。
可以这么做:
a = [[0, 0] for i in range(3)]

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/400184

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX