python中不受欢迎的列表赋值行为

时间:2012-01-11 16:02:23

标签: python list

当我执行以下命令时,我希望获得一个3x3矩阵(列表列表),其中所有单元格为零,中央单元格为1。相反,我得到一个矩阵,其中[0] [1],[1] [1]和[2] [1]位置都是一个:

a = [[0]*3]*3
a[1][1] = 1

这似乎表明矩阵中的所有单元格都指向同一个对象,这可以通过a[0] is a[1]返回“True”这一事实得到证实。实际上,如果在上面的第二个表达式之前执行,a[0][0] is a[0][1]也会返回“True”。那么,为什么不是[0] [0],[0] [2]等(第一和第三“列”中的单元格)也用新值更新?

3 个答案:

答案 0 :(得分:5)

以下内容将满足您的期望:

a = [[0]*3 for i in range(3)]

问题在于,在您的示例中,a的三个顶级元素最终引用了相同的列表,因此当您更改a的一行时,所有其他行似乎也会更改。

我建议的代码通过为a行创建三个单独的列表来进行更改。

答案 1 :(得分:3)

这是其中一个most common Python questions ever的变体,但由于此处的实际问题

  

那么,为什么不是[0] [0],[0] [2]等(第一和第三中的单元格)   “列”)也用新值更新?

有点不同,我不会投票结束。

这是因为a[0] is a[1]a[0][0] is a[0][1]略有不同。第一个是做你认为它正在做的事情:它检查两个列表a[0]a[1]是否是相同的列表 - 这两个列表是否是同一个列表的两个名称。但是,第二个问题不是检查a[0][0]a[0][1]是否指向列表中的相同条目 - 它是说a[0][0]引用的对象 },即整数0,与a[0][1]引用的对象相同,也是0.

这实际上可以返回False。实际上它返回True,因为CPython重用了小整数对象,但这并不能保证。

所以你的两个“是”检查不完全相同:虽然它们都测试引用对象的身份,但第二个测试在这种情况下没有相同的指针式含义。

答案 2 :(得分:0)

a [0] [0]是[0] [1]比较该指数的值(零)。它是相同的(整数)对象。

但是[0] [1] = 1会更改[0] [1]位置指向的对象。 包含列表a a [0]不会改变,只有指向的内容才会改变。

如果将索引视为对象的引用,则非常清楚。 a [0] [0]是[0] [1]意味着两者都引用相同的对象。 a [0] [1] = 1表示设置索引以引用“1”integet对象。