- 问题:
-
我需要用Python创建一个列表列表,因此我键入了以下内容:
myList = [[1] * 4] * 3
列表如下:
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
然后我改变了最里面的一个值:
myList[0][0] = 5
现在我的列表如下:
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
这不是我想要或期望的。有人能解释一下发生了什么事,以及如何避开它吗?在
- 答案:
-
当你写
[x]*3
时,基本上你得到了一个列表[x,x,x]
。也就是说,包含3个对同一x
的引用的列表。当您修改这个单一的x
时,它可以通过对它的所有三个引用看到:x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(l[0]): {id(l[0])}\n"
f"id(l[1]): {id(l[1])}\n"
f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]要修复它,您需要确保在每个位置都创建一个新列表。一种方法是
[[1]*4 for _ in range(3)]
它将每次重新评估
[1]*4
,而不是只评估一次,并引用1个列表3次您可能想知道为什么
*
不能像列表理解那样生成独立对象。这是因为乘法运算符*
对对象进行操作,而没有看到表达式。当使用*
将[[1]*4]
乘以3时,*
只看到1元素列表[[1]*4]
的计算结果,而不是[[1]*4
表达式文本。*
不知道如何复制该元素,也不知道如何重新评估[[1]*4]
,甚至不知道您想要复制,而且通常情况下,甚至可能没有复制元素的方法*
唯一的选择是对现有子列表进行新的引用,而不是尝试创建新的子列表。其他任何东西都是不一致的,或者需要对基本语言设计决策进行重大的重新设计相反,列表理解在每次迭代中都会重新评估元素表达式。
[[1]*4 for n in range(3)]
每次重新评估[1]*4
,原因相同[x**2 for x in range(3)]
每次重新评估x**2
。每次对[1]*4
的求值都会生成一个新的列表,因此列表理解可以满足您的需要顺便说一下,
[1]*4
也不复制[1]
的元素,但这并不重要,因为整数是不可变的。你不能像1.value=2那样把1变成2