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].
[4]*3
é essencialmente equivalente ax = 4; [x, x, x]
. É verdade, porém, que isso nunca causará nenhum problema, pois4
é imutável. Além disso, seu outro exemplo não é realmente um caso diferente.a = [x]*3; a[0] = 5
não causará problemas, mesmo quex
seja mutável, pois você não está modificandox
, apenas modificandoa
. Eu não descreveria minha resposta como enganosa ou incorreta - você não pode se dar um tiro no pé se estiver lidando com objetos imutáveis.x = 1000; lst = [x]*2; lst[0] is lst[1]
->True
. O Python não faz distinção entre objetos mutáveis e imutáveis aqui.Tutor do Python ao vivo Visualize
fonte
x
se refere. Se você fizer um objeto global exclusivo comx = object()
e em seguida, fazermatrix = [[x] * 2]
estes vem como verdadeira:matrix[0][0] is matrix[0][1]
list
), então, se umrow = [x] * 2
amatrix = [row] * 2
onde a ambas as linhas são exatamente o mesmo objeto, e agora muda para uma linha, dematrix[0][0] = y
repente, reflete na outra(matrix[0][0] is matrix[1][0]) == True
Na verdade, é exatamente isso que você esperaria. Vamos decompor o que está acontecendo aqui:
Você escreve
Isso é equivalente a:
Isso significa que
lst
é uma lista com 3 elementos, todos apontando paralst1
. Isso significa que as duas linhas a seguir são equivalentes:Como
lst[0]
nada mais élst1
.Para obter o comportamento desejado, você pode usar a compreensão da lista:
Nesse caso, a expressão é reavaliada para cada n, levando a uma lista diferente.
fonte
id(lst[0][0])
eid(lst[1][0])
ou mesmoid(lst[0])
eid(lst[1])
ou até:
Cria uma lista que referencia as
[1,1,1,1]
três vezes internas - e não três cópias da lista interna; portanto, sempre que você modificar a lista (em qualquer posição), verá a alteração três vezes.É o mesmo que este exemplo:
onde provavelmente é um pouco menos surpreendente.
fonte
Juntamente com a resposta aceita que explicou o problema corretamente, dentro da compreensão da sua lista, se Você estiver usando o python-2.x, use
xrange()
um gerador que seja mais eficiente (range()
no python 3 faz o mesmo trabalho) em_
vez da variável descartáveln
:Além disso, como uma maneira muito mais Pythonic , você pode usar
itertools.repeat()
para criar um objeto iterador de elementos repetidos:PS Usando numpy, se você só quer criar uma matriz de uns ou zeros que você pode usar
np.ones
enp.zeros
e / ou para outro uso númeronp.repeat()
:fonte
Contêineres Python contêm referências a outros objetos. Veja este exemplo:
Nisso
b
é uma lista que contém um item que é uma referência à listaa
. A listaa
é mutável.A multiplicação de uma lista por um número inteiro é equivalente a adicionar a lista a si mesma várias vezes (consulte operações comuns de sequência ). Então, continuando com o exemplo:
Podemos ver que a lista
c
agora contém duas referências à listaa
que são equivalentes ac = b * 2
.O FAQ do Python também contém explicações sobre esse comportamento: Como faço para criar uma lista multidimensional?
fonte
myList = [[1]*4] * 3
cria um objeto de lista[1,1,1,1]
na memória e copia sua referência 3 vezes. Isso é equivalente aobj = [1,1,1,1]; myList = [obj]*3
. Qualquer modificaçãoobj
será refletida em três locais, onde quer queobj
seja referenciada na lista. A afirmação correta seria:ou
O ponto importante a ser observado aqui é que o
*
operador é usado principalmente para criar uma lista de literais . Embora1
seja imutável,obj =[1]*4
ainda criará uma lista de1
repetidas 4 vezes para formar[1,1,1,1]
. Mas se for feita qualquer referência a um objeto imutável, o objeto será substituído por um novo.Isso significa que, se o fizermos
obj[1]=42
, nãoobj
será o que alguns podem supor. Isso também pode ser verificado:[1,42,1,1]
[42,42,42,42]
fonte
obj[2] = 42
substitui a referência no índice2
, em vez de alterar o objeto referenciado por esse índice, que é o quemyList[2][0] = ...
faz (myList[2]
é uma lista, e a atribuição altera a referência no índice 0 da lista). Obviamente, números inteiros não são mutáveis, mas muitos tipos de objetos são . E observe que a[....]
notação de exibição da lista também é uma forma de sintaxe literal! Não confunda objetos compostos (como listas) e escalares (como números inteiros), com objetos mutáveis vs. imutáveis.Em palavras simples, isso está acontecendo porque, em python, tudo funciona por referência ; portanto, quando você cria uma lista de listas dessa maneira, basicamente acaba com esses problemas.
Para resolver seu problema, você pode executar um dos seguintes procedimentos : 1. Use a documentação do array numpy para numpy.empty 2. Anexe a lista ao chegar a uma lista. 3. Você também pode usar o dicionário, se quiser
fonte
Vamos reescrever seu código da seguinte maneira:
Depois disso, execute o código a seguir para tornar tudo mais claro. O que o código faz é basicamente imprimir os
id
s dos objetos obtidos, o quee nos ajudará a identificá-los e analisar o que acontece:
E você obterá a seguinte saída:
Então agora vamos passo a passo. Você tem
x
qual é1
e uma única lista de elementos quey
contémx
. Seu primeiro passo éy * 4
obter uma nova listaz
, que é basicamente[x, x, x, x]
, ou seja, cria uma nova lista com 4 elementos, que são referências aox
objeto inicial . O passo final é bem parecido. Você basicamente fazz * 3
, o que é[[x, x, x, x]] * 3
e retorna[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
, pelo mesmo motivo do primeiro passo.fonte
Acho que todo mundo explica o que está acontecendo. Sugiro uma maneira de resolvê-lo:
myList = [[1 for i in range(4)] for j in range(3)]
print myList
E então você tem:
fonte
Tentando explicar de forma mais descritiva,
Operação 1:
Operação 2:
Percebeu por que a modificação do primeiro elemento da primeira lista não modificou o segundo elemento de cada lista? Isso porque
[0] * 2
realmente é uma lista de dois números e uma referência a 0 não pode ser modificada.Se você deseja criar cópias clone, tente a Operação 3:
Outra maneira interessante de criar cópias de clones, Operação 4:
fonte
@spelchekr da multiplicação de listas em Python: [[...]] * 3 faz 3 listas que se espelham quando modificadas e eu tive a mesma pergunta sobre "Por que apenas o externo * 3 cria mais referências enquanto o interno não? ? Por que não são todos os 1s? "
Aqui está a minha explicação depois de tentar o código acima:
*3
também cria referências, mas suas referências são imutáveis, algo como[&0, &0, &0]
: quando mudarli[0]
, você não poderá alterar nenhuma referência subjacente de const int0
; portanto, basta alterar o endereço de referência para o novo&1
;ma=[&li, &li, &li]
eli
é mutável; portanto, quando você ligama[0][0]=1
, ma [0] [0] é igual a&li[0]
, então todas as&li
instâncias mudam seu primeiro endereço para&1
.fonte
Ao usar a função de lista embutida, você pode fazer assim
fonte
a.insert(0,[5,1,1,1])