【问题标题】:Ids of Mutable objects in a Python List [duplicate]Python列表中可变对象的ID [重复]
【发布时间】:2017-06-07 20:32:32
【问题描述】:

我一直在 Python 中使用 [Value] * Count 符号来初始化列表。例如,[False] * 3 导致创建列表 [False, False False]。我尝试使用相同的符号来初始化列表列表。

>>>a = [[0] * 2] * 3
>>>print a
[[0, 0], [0, 0], [0, 0]]
>>>a[0][1] = 23
>>>print a
[[0, 23], [0, 23], [0, 23]]
>>>id(a[0])
139978350226680
>>>id(a[1])
139978350226680
>>>id(a[2])
139978350226680

我们可以看到,a 的元素三次引用单个列表,而不是引用三个不同的列表。 1. 为什么会这样? 2. 初始化列表列表的正确方法是什么?

之前的答案中已经指出了相同的行为:https://stackoverflow.com/a/13382804/4716199

【问题讨论】:

  • “正确”的方法是使用 for 循环或列表推导。
  • 如果您使用b = [0] * 2; a = [b] * 3,您会惊讶于a 包含3 个对b 的引用吗?
  • @PM2Ring 这是有道理的。我没有意识到 * 不会创建新副本,它只是复制参考。谢谢:)
  • 这篇文章可能对您也有帮助:Facts and myths about Python names and values,由 SO 资深人士 Ned Batchelder 撰写。
  • @PM2Ring 这篇文章很有用。感谢分享:)

标签: python python-2.7 list


【解决方案1】:

这是* 运算符在列表中的行为:它不复制,但复制引用。这是有道理的,因为通常甚至没有定义如何进行复制,所以 Python 只能复制引用,因为它是每个对象唯一拥有的东西。

如果您想构建新列表,可以使用列表推导:

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

鉴于列表包含可变对象,一般情况下使用*不是好习惯

对于像boolstr 这样的不可变对象,这是可行的,因为您不处理对象本身,而是处理生成的数组。在您的示例中,您使用了链式索引,因此您修改了内部列表。

【讨论】: