Czy ktoś może mi to wyjaśnić? To nie ma dla mnie żadnego sensu.
Kopiuję słownik do innego i edytuję drugi i oba są zmieniane. Dlaczego to się dzieje?
>>> 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
źródło
źródło
dict1
idict2
wskazać ten sam słownik.Odpowiedzi:
Python nigdy niejawnie kopiuje obiekty. Po ustawieniu
dict2 = dict1
powoduje, że odnoszą się one do tego samego dokładnie obiektu dict, więc po zmutowaniu wszystkie odniesienia do niego będą odnosić się do obiektu w jego bieżącym stanie.Jeśli chcesz skopiować dykt (co jest rzadkie), musisz to zrobić jawnie
lub
źródło
dir(1)
aby to zobaczyć), ale są domyślnie kopiowane.int
,float
abool
instancje są prawdziwymi obiektami Pythona, i b) obiekty tego typu nie są domyślnie kopiowane po ich przekazaniu, na pewno nie na poziomie semantycznym, a nawet jako szczegóły implementacji w CPython.copy.deepcopy()
zamiastdict()
lubdict.copy()
. Imran jest zwięzła odpowiedź znajduje się po prawej stronie rozsądku, w przeciwieństwie do tej odpowiedzi.Kiedy przypisujesz
dict2 = dict1
, nie tworzysz kopiidict1
, skutkujedict2
to po prostu inną nazwą dladict1
.Aby skopiować zmienne typów jak słowniki użytku
copy
/deepcopy
zcopy
modułu.źródło
Podczas gdy
dict.copy()
idict(dict1)
generuje kopię, są to tylko płytkie kopie. Jeśli potrzebujesz głębokiej kopii,copy.deepcopy(dict1)
jest wymagana. Przykład:Jeśli chodzi o płytkie i głębokie kopie, z dokumentacji modułu Python
copy
:źródło
w=copy.deepcopy(x)
to kluczowa linia.dict2 = dict1
idict2 = copy.deepcopy(dict1)
?W Pythonie 3.5+ istnieje łatwiejszy sposób na uzyskanie płytkiej kopii za pomocą ** operatora rozpakowywania. Zdefiniowany przez Pep 448 .
** rozpakowuje słownik do nowego słownika, który jest następnie przypisywany do dict2.
Możemy również potwierdzić, że każdy słownik ma odrębny identyfikator.
Jeśli potrzebna jest głęboka kopia, to copy.deepcopy () jest nadal dobrym rozwiązaniem.
źródło
dict2 = {**dict1, 'key3':'value3'}
Najlepszy i najprostszy sposób, aby utworzyć kopię o dict zarówno w Pythonie 2.7 i 3 są ...
Aby utworzyć kopię prostego (jednopoziomowego) słownika:
1. Za pomocą metody dict () zamiast generować odwołanie wskazujące na istniejący dykt.
2. Korzystanie z wbudowanej metody update () słownika python.
Aby utworzyć kopię zagnieżdżonego lub złożonego słownika:
Użyj wbudowanego modułu kopiowania , który zapewnia ogólne płytkie i głębokie operacje kopiowania. Ten moduł jest obecny zarówno w Pythonie 2.7, jak i 3. *
źródło
dict()
tworzy płytką kopię, a nie głęboką kopię. Oznacza to, że jeśli masz zagnieżdżone,dict
to zewnętrznydict
będzie kopią, ale wewnętrzny dykt będzie odniesieniem do oryginalnego wewnętrznego dykt.Możesz także utworzyć nowy słownik ze zrozumieniem słownika. Pozwala to uniknąć importowania kopii.
Oczywiście w python> = 2.7 możesz zrobić:
Ale dla kompatybilności wstecznej najlepsza metoda jest lepsza.
źródło
d2 = dict.copy(d1)
nie wymaga to również żadnego importu.d2 = d1.copy()
dict.items
zwraca już iterowalną parę klucz / wartość. Więc możesz po prostu użyćdict(mydict.items())
(możesz też po prostu użyćdict(mydict)
). Przydatne może być zrozumienie, jeśli chcesz filtrować wpisy.Oprócz innych dostarczonych rozwiązań można użyć
**
do zintegrowania słownika z pustym słownikiem, np.shallow_copy_of_other_dict = {**other_dict}
.Teraz będziesz mieć „płytką” kopię
other_dict
.Dotyczy twojego przykładu:
Wskaźnik: Różnica między płytkimi a głębokimi kopiami
źródło
Instrukcje przypisania w Pythonie nie kopiują obiektów, tworzą powiązania między celem a obiektem.
Więc
dict2 = dict1
, wynika inny wiązania pomiędzydict2
i obiekt, którydict1
odnosi się do.jeśli chcesz skopiować nagranie, możesz użyć
copy module
. Moduł kopiowania ma dwa interfejsy:Różnica między płytkim a głębokim kopiowaniem dotyczy tylko obiektów złożonych (obiektów zawierających inne obiekty, takich jak listy lub instancje klas):
Płytkie kopii tworzy nowy obiekt, a następnie związek (w zakresie możliwym) wkłada odniesień do niej na przedmioty znajdujące się w oryginale.
ZA Głęboka kopia konstruuje nowy obiekt związek, a następnie rekurencyjnie, wkładki do niego kopie obiektów znalezionych w oryginale.
Na przykład w python 2.7.9:
a wynikiem jest:
źródło
Możesz skopiować i edytować nowo utworzoną kopię za jednym razem, wywołując
dict
konstruktor z dodatkowymi argumentami słów kluczowych:źródło
Początkowo to też mnie zdezorientowało, ponieważ pochodziłem z języka C.
W C zmienna jest lokalizacją w pamięci o zdefiniowanym typie. Przypisanie do zmiennej kopiuje dane do lokalizacji pamięci zmiennej.
Ale w Pythonie zmienne działają bardziej jak wskaźniki do obiektów. Zatem przypisanie jednej zmiennej do drugiej nie tworzy kopii, po prostu sprawia, że nazwa zmiennej wskazuje na ten sam obiekt.
źródło
Każda zmienna w pythonie (rzeczy takie jak
dict1
lubstr
lub__builtins__
jest wskaźnikiem do jakiegoś ukrytego platońskiego „obiektu” wewnątrz maszyny.Jeśli ustawisz
dict1 = dict2
, po prostu wskażeszdict1
ten sam obiekt (lub lokalizację pamięci lub dowolną analogię), jakdict2
. Teraz obiekt, do którego następuje odwołanie,dict1
to ten sam obiekt, do którego odnosi siędict2
.Możesz sprawdzić:
dict1 is dict2
powinno byćTrue
. Ponadtoid(dict1)
powinien być taki sam jakid(dict2)
.Chcesz
dict1 = copy(dict2)
lubdict1 = deepcopy(dict2)
.Różnica między
copy
ideepcopy
?deepcopy
upewni się, że elementydict2
(czy wskazałeś na listę?) są również kopiami.Nie używam
deepcopy
dużo - zwykle słabą praktyką jest pisanie kodu, który tego wymaga (moim zdaniem).źródło
dict1
jest symbolem, który odwołuje się do podstawowego obiektu słownika. Przypisaniedict1
dodict2
jedynie przypisania tego samego odwołania. Zmiana wartości klucza za pomocądict2
symbolu zmienia podstawowy obiekt, co również ma wpływdict1
. To jest mylące.O wiele łatwiej jest wnioskować o niezmiennych wartościach niż referencjach, więc rób kopie, gdy tylko jest to możliwe:
Jest to składniowo to samo, co:
źródło
dict2 = dict1
nie kopiuje słownika. To po prostu daje programiście drugi sposób (dict2
) na odniesienie do tego samego słownika.źródło
Istnieje wiele sposobów kopiowania obiektu Dict, po prostu używam
źródło
dict_2 = dict_1.copy()
jest znacznie bardziej wydajny i logiczny.Jak wyjaśnili inni, wbudowane narzędzie
dict
nie robi tego, co chcesz. Ale w Python2 (i prawdopodobnie również 3) możesz łatwo utworzyćValueDict
klasę, z=
którą będziesz kopiować, aby mieć pewność, że oryginał się nie zmieni.Proszę odnieść się do omawianego tutaj wzoru modyfikacji wartości: Python 2.7 - czysta składnia dla modyfikacji wartości . Kluczem jest to, że obserwacja
str
iint
zachowywać się jak wartości w Pythonie (choć są one rzeczywiście niezmienne obiekty pod maską). Obserwując to, zauważ również, że nic nie jest magicznie wyjątkowe wstr
lubint
.dict
mogą być używane w ten sam sposób i mogę myśleć o wielu przypadkach, w którychValueDict
ma to sens.źródło
poniższy kod, który jest na dyktando, który postępuje zgodnie ze składnią Json ponad 3 razy szybciej niż deepcopy
źródło
natknąłem się na szczególne zachowanie podczas próby głębokiego skopiowania właściwości słownika klasy bez przypisywania jej do zmiennej
new = copy.deepcopy(my_class.a)
nie działa, tj. modyfikowanienew
modyfikacjimy_class.a
ale jeśli to zrobisz,
old = my_class.a
a następnienew = copy.deepcopy(old)
zadziała to idealnie, tj. modyfikacjanew
nie ma wpływumy_class.a
Nie jestem pewien, dlaczego tak się dzieje, ale mam nadzieję, że pomoże to zaoszczędzić kilka godzin! :)
źródło
my_class.a
?ponieważ dict2 = dict1, dict2 zawiera odniesienie do dict1. Zarówno dict1, jak i dict2 wskazują to samo miejsce w pamięci. Jest to normalny przypadek podczas pracy ze zmiennymi obiektami w Pythonie. Podczas pracy ze zmiennymi obiektami w Pythonie musisz być ostrożny, ponieważ trudno jest debugować. Tak jak w poniższym przykładzie.
Ten przykładowy zamiar polega na uzyskaniu wszystkich identyfikatorów użytkowników, w tym identyfikatorów zablokowanych. Otrzymaliśmy to ze zmiennej ids, ale również przypadkowo zaktualizowaliśmy wartość my_users . kiedy rozszerzyłeś identyfikatory za pomocą block_ids, my_users zostali zaktualizowani, ponieważ identyfikatory odnoszą się do my_users .
źródło
Kopiowanie przy użyciu pętli for:
źródło
deepcopy
, który jest zbudowany specjalnie do tego celu?Możesz użyć bezpośrednio:
gdzie obiekt dict2 jest niezależną kopią dict1, więc możesz modyfikować dict2 bez wpływu na dict1.
Działa to dla każdego rodzaju obiektu.
źródło
__repr__
do odtworzenia przez eval, ani klasa obiektu nie może być w bieżącym zakresie, który ma zostać wywołany. Nawet trzymanie się wbudowanych typów, to się nie powiedzie, jeśli ten sam obiekt jest przechowywany pod wieloma kluczami, tak jakdict2
wtedy, gdyby miały dwa oddzielne obiekty.dict1
Zamiast tego będzie zawierał samoreferencyjny słownik, w którym się zawieraEllipsis
. Lepiej byłoby użyćdict1.copy()