Quando você escreve [x]*3
, obtém, essencialmente, a lista [x, x, x]
. Ou seja, uma lista com 3 referências à mesma x
. Quando você modifica este single, x
ele fica visível através das três referências a ele:
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]]
Para corrigi-lo, você precisa criar uma nova lista em cada posição. Uma maneira de fazer isso é
[[1]*4 for _ in range(3)]
que reavaliará [1]*4
cada vez em vez de avaliar uma vez e fazer 3 referências a 1 lista.
Você pode se perguntar por *
que não consegue criar objetos independentes da mesma forma que a compreensão da lista. Isso ocorre porque o operador de multiplicação *
opera em objetos, sem ver expressões. Quando você *
multiplica [[1] * 4]
por 3, *
vê apenas a lista de 1 elemento [[1] * 4]
avaliada, não o [[1] * 4
texto da expressão. *
não tem idéia de como fazer cópias desse elemento, não tem idéia de como reavaliar [[1] * 4]
e não tem idéia de que você deseja cópias e, em geral, pode não haver uma maneira de copiar o elemento.
A única opção *
é fazer novas referências à sublist existente, em vez de tentar criar novas sublistas. Qualquer outra coisa seria inconsistente ou exigiria uma grande reformulação das decisões fundamentais de design de linguagem.
Por outro lado, uma compreensão de lista reavalia a expressão do elemento em cada iteração. [[1] * 4 for n in range(3)]
reavalia [1] * 4
todas as vezes pelo mesmo motivo [x**2 for x in range(3)]
reavalia x**2
todas as vezes. Toda avaliação de [1] * 4
gera uma nova lista, portanto a compreensão da lista faz o que você queria.
Aliás, [1] * 4
também não copia os elementos de [1]
, mas isso não importa, pois os números inteiros são imutáveis. Você não pode fazer algo assim 1.value = 2
e transformar 1 em 2.
[x]*3
armazenar 3 referências como[x, x, x]
só é correto quandox
é mutável. Este trabalho does't para, por exemploa=[4]*3
, onde depoisa[0]=5
,a=[5,4,4].