我希望输出像 [[0,0,0,0,],[0,1,0,0],[0,2,0,0],[0,3,0,0]]
I would expect the output to be like [[0,0,0,0,],[0,1,0,0],[0,2,0,0],[0,3,0,0]]
time_count = [[0, 0, 0, 0]] * 4
j = 0
for i in range(len(time_count)):
time_count[i][1] = j
j += 1
print(time_count)
输出:
[[0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0]]
我希望输出如下:
[[0,0,0,0],[0,1,0,0],[0,2,0,0],[0,3,0,0]]
有人可以解释为什么每个 index[1]
都是 3
吗?
轻松修复:
time_count = [[0, 0, 0, 0] for _ in range(4)]
正如 Klaus D. 所暗示的,在嵌套列表上使用 *
运算符通常不是一个好主意,因为它通过复制引用来复制内容。在乘以不可变类型的序列时,您不会注意到这一点,例如一个整数列表,但是当元素可变时,你会得到重复项。
做:
time_count = [[0, 0, 0, 0]] * 4
print([[v if x!=1 else i for x,v in enumerate(a)] for i,a in enumerate(time_count)])
输出:
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 2, 0, 0], [0, 3, 0, 0]]
更新:
解释:
使用enumerate
遍历列表time_count
.
的索引和值
再次使用 enumerate
遍历列表 a
的索引和值。 这是 time_count
.
的迭代器
遍历 a
的索引并说 i
(time_count
的索引迭代器)如果 x
([ 的索引迭代器) =15=]) 是 1,否则说 v
(a
的迭代器)
注意:这都是列表理解
* 运算符只是创建对原始列表的新引用(此处 [0, 0, 0, 0]
)。
如果将原始列表更改为 time_count[i][1] = j
,则所有引用都会反映相同的更改。
如果你想创建一个新列表,你可以使用带有循环的扩展方法:
time_count = []
time_count.extend([0,0,0,0] for _ in range(4))
现在,time_count中的所有元素列表存储单独的内存并且可以有不同的值。
列表写成[[0, 0, 0, 0]]*4 不好。列表是可变的。每次更改任何列表元素时,它的所有副本都会更改。一种好的写法如下所示,因为那样你就不会复制列表元素。
[[0, 0, 0, 0] for i in range(4)]
基本上,列表的实体是指向特定内存位置的指针。当将 list(a) 分配给 list(b) 时,这意味着 list(b) 指向与 list(a) 相同的内存位置。
a = [1, 2, 3]
b = a
a = [3, 4, 5]
print(a, b)
[3, 4, 5] [1, 2, 3]
在上述问题中,如果嵌套列表内部乘以4倍,则所有子列表都指向相同的内存位置。因此,如果更改了其中一个子列表,则更改会传播到所有子列表,这基本上会在代码执行时产生意外结果。对于任何有兴趣了解更多的人,
该视频总结了列表的所有不明显的基本特征。它还进一步详细解释了上述问题。
https://www.youtube.com/watch?v=_AEJHKGk9ns
time_count = [[0, 0, 0, 0]] * 4
j = 0
for i in range(len(time_count)):
time_count[i][1] = j
j += 1
print(time_count)
输出:
[[0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0], [0, 3, 0, 0]]
我希望输出如下:
[[0,0,0,0],[0,1,0,0],[0,2,0,0],[0,3,0,0]]
有人可以解释为什么每个 index[1]
都是 3
吗?
轻松修复:
time_count = [[0, 0, 0, 0] for _ in range(4)]
正如 Klaus D. 所暗示的,在嵌套列表上使用 *
运算符通常不是一个好主意,因为它通过复制引用来复制内容。在乘以不可变类型的序列时,您不会注意到这一点,例如一个整数列表,但是当元素可变时,你会得到重复项。
做:
time_count = [[0, 0, 0, 0]] * 4
print([[v if x!=1 else i for x,v in enumerate(a)] for i,a in enumerate(time_count)])
输出:
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 2, 0, 0], [0, 3, 0, 0]]
更新:
解释:
使用
enumerate
遍历列表time_count
. 的索引和值
再次使用
enumerate
遍历列表a
的索引和值。 这是time_count
. 的迭代器
遍历
a
的索引并说i
(time_count
的索引迭代器)如果x
([ 的索引迭代器) =15=]) 是 1,否则说v
(a
的迭代器)
注意:这都是列表理解
* 运算符只是创建对原始列表的新引用(此处 [0, 0, 0, 0]
)。
如果将原始列表更改为 time_count[i][1] = j
,则所有引用都会反映相同的更改。
如果你想创建一个新列表,你可以使用带有循环的扩展方法:
time_count = []
time_count.extend([0,0,0,0] for _ in range(4))
现在,time_count中的所有元素列表存储单独的内存并且可以有不同的值。
列表写成[[0, 0, 0, 0]]*4 不好。列表是可变的。每次更改任何列表元素时,它的所有副本都会更改。一种好的写法如下所示,因为那样你就不会复制列表元素。
[[0, 0, 0, 0] for i in range(4)]
基本上,列表的实体是指向特定内存位置的指针。当将 list(a) 分配给 list(b) 时,这意味着 list(b) 指向与 list(a) 相同的内存位置。
a = [1, 2, 3]
b = a
a = [3, 4, 5]
print(a, b)
[3, 4, 5] [1, 2, 3]
在上述问题中,如果嵌套列表内部乘以4倍,则所有子列表都指向相同的内存位置。因此,如果更改了其中一个子列表,则更改会传播到所有子列表,这基本上会在代码执行时产生意外结果。对于任何有兴趣了解更多的人, 该视频总结了列表的所有不明显的基本特征。它还进一步详细解释了上述问题。 https://www.youtube.com/watch?v=_AEJHKGk9ns