Bisakah seseorang tolong jelaskan hal ini kepada saya? Ini tidak masuk akal bagi saya.
Saya menyalin kamus ke kamus lain dan mengedit kamus kedua dan keduanya diubah. Mengapa ini terjadi?
>>> 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
sumber
sumber
dict1
dandict2
menunjuk ke dikt yang sama.Jawaban:
Python tidak pernah secara implisit menyalin objek. Ketika Anda mengatur
dict2 = dict1
, Anda membuat mereka merujuk ke objek dict yang sama persis, jadi ketika Anda memutasikannya, semua referensi padanya tetap merujuk ke objek dalam keadaan saat ini.Jika Anda ingin menyalin dikt (yang jarang), Anda harus melakukannya secara eksplisit
atau
sumber
dir(1)
untuk melihat itu), tetapi mereka disalin secara implisit.int
,,float
danbool
instance adalah objek Python sungguhan, dan b) objek jenis ini tidak disalin secara implisit ketika Anda melewatinya, tidak pada level semantik Python pasti dan bahkan tidak sebagai detail implementasi dalam CPython.copy.deepcopy()
daripadadict()
ataudict.copy()
. Imran 's jawaban singkat adalah di sisi kanan kewarasan, tidak seperti jawaban ini.Ketika Anda menetapkan
dict2 = dict1
, Anda tidak membuat salinandict1
, itudict2
hanya menjadi nama lain untukdict1
.Untuk menyalin tipe yang bisa berubah-ubah seperti kamus, gunakan
copy
/deepcopy
daricopy
modul.sumber
Sementara
dict.copy()
dandict(dict1)
menghasilkan salinan, mereka hanya salinan dangkal . Jika Anda ingin salinan yang dalam ,copy.deepcopy(dict1)
diperlukan. Sebuah contoh:Mengenai salinan dangkal vs dalam, dari modul Python
copy
docs :sumber
w=copy.deepcopy(x)
adalah kunci utama.dict2 = dict1
dandict2 = copy.deepcopy(dict1)
?Pada python 3.5+ ada cara yang lebih mudah untuk mendapatkan salinan yang dangkal dengan menggunakan operator pembungkusan **. Didefinisikan oleh Pep 448 .
** membongkar kamus ke kamus baru yang kemudian ditugaskan ke dict2.
Kami juga dapat mengonfirmasi bahwa setiap kamus memiliki id berbeda.
Jika salinan yang dalam diperlukan, maka copy.deepcopy () masih merupakan cara yang harus dilakukan.
sumber
dict2 = {**dict1, 'key3':'value3'}
Yang terbaik dan cara termudah untuk membuat salinan dari dict di kedua Python 2,7 dan 3 yang ...
Untuk membuat salinan kamus sederhana (level tunggal):
1. Menggunakan metode dict () , alih-alih menghasilkan referensi yang menunjuk ke dict yang ada.
2. Menggunakan metode pemutakhiran () kamus python bawaan.
Untuk membuat salinan kamus bersarang atau kompleks:
Gunakan modul salin internal , yang menyediakan operasi salin dangkal dan dalam generik. Modul ini hadir dalam Python 2.7 dan 3. *
sumber
dict()
menciptakan salinan dangkal bukan salinan dalam. Berarti bahwa jika Anda memiliki sarangdict
maka bagian luardict
akan menjadi salinan tetapi bagian dalam akan menjadi referensi ke bagian dalam yang asli.Anda juga bisa membuat kamus baru dengan pemahaman kamus. Ini menghindari mengimpor salinan.
Tentu saja dengan python> = 2.7 yang dapat Anda lakukan:
Tetapi untuk compat mundur., Metode teratas lebih baik.
sumber
d2 = dict.copy(d1)
tidak memerlukan impor apa pun.d2 = d1.copy()
dict.items
sudah mengembalikan pasangan kunci / nilai iterable. Jadi Anda bisa menggunakandict(mydict.items())
(Anda juga bisa menggunakandict(mydict)
). Mungkin bermanfaat untuk memiliki pemahaman jika Anda ingin memfilter entri.Selain solusi lain yang disediakan, Anda dapat menggunakan
**
untuk mengintegrasikan kamus ke dalam kamus kosong, misalnya,shallow_copy_of_other_dict = {**other_dict}
.Sekarang Anda akan memiliki salinan "dangkal"
other_dict
.Diterapkan pada contoh Anda:
Pointer: Perbedaan antara copys dangkal dan dalam
sumber
Pernyataan penugasan dalam Python tidak menyalin objek, mereka membuat ikatan antara target dan objek.
jadi,,
dict2 = dict1
itu menghasilkan pengikatan lain antaradict2
dan objek itudict1
merujuk.jika Anda ingin menyalin sebuah dikt, Anda dapat menggunakan
copy module
. Modul salin memiliki dua antarmuka:Perbedaan antara penyalinan dangkal dan dalam hanya relevan untuk objek majemuk (objek yang berisi objek lain, seperti daftar atau instance kelas):
Sebuah salinan dangkal membangun sebuah objek senyawa baru dan kemudian (sejauh mungkin) memasukkan referensi ke dalamnya untuk benda yang ditemukan dalam bahasa aslinya.
Sebuah salinan dalam membangun sebuah objek senyawa baru dan kemudian, secara rekursif, menyisipkan salinan ke dalamnya benda-benda yang ditemukan di aslinya.
Misalnya, dalam python 2.7.9:
dan hasilnya adalah:
sumber
Anda dapat menyalin dan mengedit salinan yang baru dibuat dalam sekali jalan dengan memanggil
dict
konstruktor dengan argumen kata kunci tambahan:sumber
Ini membingungkan saya juga, pada awalnya, karena saya berasal dari latar belakang C.
Dalam C, variabel adalah lokasi di memori dengan tipe yang ditentukan. Menetapkan ke variabel menyalin data ke lokasi memori variabel.
Tetapi dalam Python, variabel bertindak lebih seperti pointer ke objek. Jadi menugaskan satu variabel ke variabel lain tidak membuat salinan, itu hanya membuat nama variabel menunjuk ke objek yang sama.
sumber
Setiap variabel dalam python (hal-hal seperti
dict1
ataustr
atau__builtins__
adalah pointer ke beberapa "objek" platonis tersembunyi di dalam mesin.Jika Anda mengatur
dict1 = dict2
, Anda hanya menunjukdict1
ke objek yang sama (atau lokasi memori, atau analogi apa pun yang Anda suka)dict2
. Sekarang, objek yang dirujuk olehdict1
adalah objek yang sama yang dirujuk olehdict2
.Anda dapat memeriksa:
dict1 is dict2
seharusnyaTrue
. Juga,id(dict1)
harus sama denganid(dict2)
.Anda mau
dict1 = copy(dict2)
, ataudict1 = deepcopy(dict2)
.Perbedaan antara
copy
dandeepcopy
?deepcopy
akan memastikan bahwa elemendict2
(apakah Anda mengarahkannya pada daftar?) juga merupakan salinan.Saya tidak menggunakan
deepcopy
banyak - biasanya praktik buruk untuk menulis kode yang membutuhkannya (menurut saya).sumber
dict1
adalah simbol yang merujuk objek kamus yang mendasarinya. Menugaskandict1
untukdict2
hanya memberikan referensi yang sama. Mengubah nilai kunci melaluidict2
simbol akan mengubah objek yang mendasarinya, yang juga memengaruhidict1
. Ini membingungkan.Jauh lebih mudah untuk beralasan tentang nilai-nilai yang tidak dapat diubah daripada referensi, jadi buatlah salinan bila memungkinkan:
Secara sintaksis sama dengan:
sumber
dict2 = dict1
tidak menyalin kamus. Ini hanya memberi Anda programmer cara kedua (dict2
) untuk merujuk ke kamus yang sama.sumber
Ada banyak cara untuk menyalin objek Dict, saya hanya menggunakan
sumber
dict_2 = dict_1.copy()
jauh lebih efisien dan logis.Seperti yang dijelaskan orang lain, built-in
dict
tidak melakukan apa yang Anda inginkan. Tetapi dalam Python2 (dan mungkin 3 juga) Anda dapat dengan mudah membuatValueDict
kelas yang menyalin=
sehingga Anda dapat yakin bahwa yang asli tidak akan berubah.Lihat pola modifikasi nilai yang dibahas di sini: Python 2.7 - sintaksis bersih untuk modifikasi nilai . Pengamatan utama adalah itu
str
danint
berperilaku sebagai nilai-nilai dalam Python (meskipun mereka sebenarnya benda abadi di bawah tenda). Saat Anda mengamati itu, harap perhatikan juga bahwa tidak ada yang istimewastr
atau ajaibint
.dict
dapat digunakan dalam banyak cara yang sama, dan saya bisa memikirkan banyak kasus di manaValueDict
masuk akal.sumber
kode berikut, yaitu pada dikt yang mengikuti sintaks json lebih dari 3 kali lebih cepat dari deepcopy
sumber
saya berlari ke perilaku aneh ketika mencoba untuk mendalami properti kamus dari kelas tanpa menetapkannya ke variabel
new = copy.deepcopy(my_class.a)
tidak berfungsi yaitu memodifikasinew
memodifikasimy_class.a
tetapi jika Anda melakukannya
old = my_class.a
dannew = copy.deepcopy(old)
berfungsi dengan baik yaitu memodifikasinew
tidak mempengaruhimy_class.a
Saya tidak yakin mengapa ini terjadi, tetapi saya harap ini bisa menghemat waktu! :)
sumber
my_class.a
?karena, dict2 = dict1, dict2 memegang referensi ke dict1. Kedua dict1 dan dict2 menunjuk ke lokasi yang sama dalam memori. Ini hanya kasus normal saat bekerja dengan objek yang bisa berubah dalam python. Ketika Anda bekerja dengan objek yang bisa berubah dalam python Anda harus berhati-hati karena sulit untuk debug. Seperti contoh berikut ini.
Niat contoh ini adalah untuk mendapatkan semua id pengguna termasuk id yang diblokir. Itu kami dapatkan dari variabel id tetapi kami juga memperbarui nilai my_users secara tidak sengaja. ketika Anda memperpanjang id dengan blok_id, my_users diperbarui karena id merujuk ke my_users .
sumber
Menyalin dengan menggunakan for for:
sumber
deepcopy
, yang dibangun secara tegas untuk tujuan ini?Anda dapat menggunakan secara langsung:
di mana objek dict2 adalah salinan independen dict1, sehingga Anda dapat memodifikasi dict2 tanpa mempengaruhi dict1.
Ini berfungsi untuk semua jenis objek.
sumber
__repr__
untuk direkonstruksi dengan eval, juga tidak mungkin kelas objek berada dalam ruang lingkup saat ini untuk dipanggil. Bahkan tetap dengan tipe built-in, ini akan gagal jika objek yang sama disimpan di bawah beberapa tombol, karenadict2
kemudian akan memiliki dua objek terpisah. Kamus referensial mandiri, yangdict1
berisi kamus itu sendiri, akan berisi kamus tersebutEllipsis
. Akan lebih baik menggunakandict1.copy()