Alguém pode explicar isso para mim? Isso não faz nenhum sentido para mim.
Copio um dicionário para outro e edito o segundo e ambos são alterados. Por que isso está acontecendo?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
python
python-3.x
dictionary
reference
MadSc13ntist
fonte
fonte
dict1
edict2
apontar para o mesmo ditado.Respostas:
Python nunca copia implicitamente objetos. Quando você define
dict2 = dict1
, está fazendo com que eles se refiram ao mesmo objeto de ditado exato; portanto, quando você o modifica, todas as referências a ele continuam se referindo ao objeto em seu estado atual.Se você deseja copiar o ditado (o que é raro), é necessário fazê-lo explicitamente com
ou
fonte
dir(1)
para ver isso), mas são copiados implicitamente.int
,float
, Ebool
casos são reais Python objetos, e b) objetos desses tipos não são copiados implicitamente quando você passá-los, e não em um nível Python semântica com certeza e nem mesmo como um detalhe de implementação em CPython.copy.deepcopy()
vez dedict()
oudict.copy()
. A resposta concisa de Imran está do lado certo da sanidade, ao contrário desta resposta.Quando você atribui
dict2 = dict1
, não está fazendo uma cópiadict1
, isso resulta emdict2
apenas outro nome paradict1
.Para copiar os tipos mutáveis, como dicionários, use
copy
/deepcopy
docopy
módulo.fonte
Enquanto
dict.copy()
edict(dict1)
gera uma cópia, elas são apenas cópias rasas . Se você deseja uma cópia profunda ,copy.deepcopy(dict1)
é necessária. Um exemplo:Em relação às cópias rasas e profundas, do módulo Python
copy
docs :fonte
w=copy.deepcopy(x)
é a linha principal.dict2 = dict1
edict2 = copy.deepcopy(dict1)
?No python 3.5+, há uma maneira mais fácil de obter uma cópia superficial usando o ** operador de descompactação. Definido pelo Pep 448 .
** descompacta o dicionário em um novo dicionário que é atribuído ao dict2.
Também podemos confirmar que cada dicionário tem um ID distinto.
Se uma cópia profunda for necessária, então copy.deepcopy () ainda é o caminho a percorrer.
fonte
dict2 = {**dict1, 'key3':'value3'}
As melhores e as maneiras mais fáceis de criar uma cópia de um dict no Python 2.7 e 3 são ...
Para criar uma cópia do dicionário simples (nível único):
1. Usando o método dict () , em vez de gerar uma referência que aponte para o dict existente.
2. Usando o método update () interno do dicionário python.
Para criar uma cópia do dicionário aninhado ou complexo:
Use o módulo de cópia embutido , que fornece operações genéricas de cópia superficial e profunda. Este módulo está presente no Python 2.7 e 3. *
fonte
dict()
cria uma cópia superficial e não profunda. Significando que se você tiver um aninhadodict
, o exteriordict
será uma cópia, mas o ditado interno será uma referência ao ditado interno original.Você também pode criar um novo dicionário com uma compreensão do dicionário. Isso evita a importação de cópia.
Obviamente, em python> = 2.7, você pode fazer:
Mas para compatibilidade com versões anteriores, o método top é melhor.
fonte
d2 = dict.copy(d1)
também não exige nenhuma importação.d2 = d1.copy()
dict.items
já retorna um par de chave / valor iterável. Então você pode apenas usardict(mydict.items())
(você também pode apenas usardict(mydict)
). Pode ser útil ter compreensão se você deseja filtrar as entradas.Além das outras soluções fornecidas, você pode usar
**
para integrar o dicionário em um dicionário vazio, por exemplo,shallow_copy_of_other_dict = {**other_dict}
.Agora você terá uma cópia "rasa" de
other_dict
.Aplicado ao seu exemplo:
Ponteiro: Diferença entre cópias rasas e profundas
fonte
As instruções de atribuição no Python não copiam objetos, elas criam ligações entre um destino e um objeto.
portanto,
dict2 = dict1
resulta em outra ligação entredict2
e o objeto quedict1
refere.Se você deseja copiar um ditado, pode usar o
copy module
. O módulo de cópia possui duas interfaces:A diferença entre cópia superficial e profunda é relevante apenas para objetos compostos (objetos que contêm outros objetos, como listas ou instâncias de classe):
Uma cópia superficial constrói um novo objeto composto e, em seguida, (na medida do possível) insere referências aos objetos encontrados no original.
Uma cópia profunda constrói um novo objeto composto e, em seguida, recursivamente, insere cópias dos objetos encontrados no original.
Por exemplo, no python 2.7.9:
e o resultado é:
fonte
Você pode copiar e editar a cópia recém-construída de uma só vez, chamando o
dict
construtor com argumentos adicionais de palavras-chave:fonte
Isso também me confundiu, inicialmente, porque eu era proveniente de um fundo C.
Em C, uma variável é um local na memória com um tipo definido. A atribuição a uma variável copia os dados no local de memória da variável.
Mas no Python, variáveis agem mais como ponteiros para objetos. Portanto, atribuir uma variável a outra não faz uma cópia, apenas faz o nome da variável apontar para o mesmo objeto.
fonte
Toda variável em python (coisas como
dict1
oustr
ou__builtins__
é um ponteiro para algum "objeto" platônico oculto dentro da máquina.Se você definir
dict1 = dict2
, basta apontardict1
para o mesmo objeto (ou local da memória ou qualquer analogia que desejar) comodict2
. Agora, o objeto referenciado pordict1
é o mesmo objeto referenciado pordict2
.Você pode verificar:
dict1 is dict2
deve serTrue
. Além disso,id(dict1)
deve ser o mesmo queid(dict2)
.Você quer
dict1 = copy(dict2)
oudict1 = deepcopy(dict2)
.A diferença entre
copy
edeepcopy
?deepcopy
garantirá que os elementos dedict2
(você apontou para uma lista?) também sejam cópias.Não uso
deepcopy
muito - geralmente é uma prática ruim escrever código que seja necessário (na minha opinião).fonte
dict1
é um símbolo que faz referência a um objeto de dicionário subjacente. Atribuirdict1
adict2
apenas atribui a mesma referência. Alterar o valor de uma chave por meio dodict2
símbolo altera o objeto subjacente, o que também afetadict1
. Isso é confuso.É muito mais fácil argumentar sobre valores imutáveis do que referências, portanto, faça cópias sempre que possível:
É sintaticamente o mesmo que:
fonte
dict2 = dict1
não copia o dicionário. Simplesmente fornece ao programador uma segunda maneira (dict2
) de se referir ao mesmo dicionário.fonte
Existem muitas maneiras de copiar o objeto Dict, eu simplesmente uso
fonte
dict_2 = dict_1.copy()
é muito mais eficiente e lógico.Como outros explicaram, o built-in
dict
não faz o que você deseja. Porém, no Python2 (e provavelmente também no 3), você pode criar facilmente umaValueDict
classe que copia=
para ter certeza de que o original não será alterado.Por favor, consulte o padrão de modificação lvalue discutido aqui: Python 2.7 - sintaxe limpa para modificação de lvalue . A principal observação é essa
str
eint
se comporta como valores em Python (mesmo que sejam objetos imutáveis sob o capô). Enquanto você observa isso, observe também que nada é magicamente especial sobrestr
ouint
.dict
pode ser usado da mesma maneira, e posso pensar em muitos casos em queValueDict
faz sentido.fonte
o código a seguir, que está no dict, que segue a sintaxe json mais de 3 vezes mais rápido que a cópia em profundidade
fonte
Corri para um comportamento peculiar ao tentar copiar profundamente a propriedade do dicionário da classe sem atribuí-la à variável
new = copy.deepcopy(my_class.a)
não funciona, ou seja, modificarnew
modificamy_class.a
mas se você faz
old = my_class.a
e entãonew = copy.deepcopy(old)
ele funciona perfeitamente, ou seja, modificarnew
não afetamy_class.a
Não sei por que isso acontece, mas espero que ajude a economizar algumas horas! :)
fonte
my_class.a
?porque, dict2 = dict1, dict2 mantém a referência a dict1. O dict1 e o dict2 apontam para o mesmo local na memória. Este é apenas um caso normal ao trabalhar com objetos mutáveis em python. Ao trabalhar com objetos mutáveis em python, você deve ter cuidado, pois é difícil depurar. Como o exemplo a seguir.
Este exemplo de intenção é obter todos os IDs de usuário, incluindo IDs bloqueados. Obtivemos da variável ids, mas também atualizamos o valor de my_users sem intenção. quando você estendeu os ids com blocked_ids my_users foi atualizado porque ids consulte my_users .
fonte
Copiando usando um loop for:
fonte
deepcopy
, que é construído expressamente para esse fim?Você pode usar diretamente:
em que o objeto dict2 é uma cópia independente do dict1, para que você possa modificar o dict2 sem afetar o dict1.
Isso funciona para qualquer tipo de objeto.
fonte
__repr__
para ser reconstruído por eval, nem a classe do objeto pode estar no escopo atual a ser chamado. Mesmo aderindo a tipos internos, isso falhará se o mesmo objeto for armazenado em várias chaves, poisdict2
haveria dois objetos separados. Um dicionário auto-referencial, onde sedict1
contém, irá conterEllipsis
. Seria melhor usardict1.copy()