Python "memperpanjang" untuk kamus

463

Mana cara terbaik untuk memperluas kamus dengan kamus lain? Contohnya:

>>> a = { "a" : 1, "b" : 2 }
>>> b = { "c" : 3, "d" : 4 }
>>> a
{'a': 1, 'b': 2}
>>> b
{'c': 3, 'd': 4}

Saya mencari operasi apa pun untuk mendapatkan forloop yang menghindari ini :

{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

Saya ingin melakukan sesuatu seperti:

a.extend(b)  # This does not work
FerranB
sumber
25
Aku tahu untuk daftar [], maka saya supose mungkin bekerja untuk orang lain, tidak extrange ;-)
FerranB

Jawaban:

695
a.update(b)

Dokumentasi Perpustakaan Standar Python Terbaru

Nick Fortescue
sumber
6
Setelah membaca dokumen, orang akan mengerti mengapa ada "pembaruan" tetapi tidak ada "ekstensi".
georg
58
perlu diingat bahwa pembaruan () langsung memodifikasi dict dan mengembalikan None.
e18r
5
Tetapi bagaimana jika Anda hanya ingin memperluas dikt dengan nilai-nilai yang belum didefinisikan (yaitu tidak menimpa nilai yang ada)? Misalnya, perbarui dict {"a":2, "b":3}dengan dict {"b":4, "c":5}ke dict {"a":2, "b":3,"c":5}? Tentu saja mungkin menggunakan update()dengan memindahkan beberapa barang, tetapi akan lebih baik jika itu dapat dicapai hanya dalam satu baris ...
Nearoo
17
@NoNoo - cukup perbarui sebaliknya; alih-alih x.update (y) [yang akan menimpa nilai x dengan y], gunakan y.update (x) [yang menimpa nilai-nilai y dengan x] dan gunakan y sebagai dict pilihan Anda untuk operasi lebih lanjut
jonathanl
perlu diingat bahwa updatediam - diam menimpa entri yang ada. Yaitu, nilai apa pun dalam bmenimpa mereka auntuk tumpang tindih kunci.
CGFoX
186

Permata indah dalam pertanyaan tertutup ini :

"Cara oneliner", yang tidak mengubah kedua input dicts, adalah

basket = dict(basket_one, **basket_two)

Pelajari apa **basket_two(yang **) berarti di sini .

Jika terjadi konflik, item dari basket_twoakan menimpa item dari basket_one. Saat one-liners berjalan, ini sangat mudah dibaca dan transparan, dan saya tidak memiliki komplain terhadap penggunaannya setiap kali sebuah dikt yang merupakan campuran dari dua lainnya sangat berguna (pembaca mana saja yang kesulitan memahaminya akan dilayani dengan sangat baik oleh cara ini mendorongnya untuk belajar tentang dictdan **formulir ;-). Jadi, misalnya, gunakan seperti:

x = mungesomedict(dict(adict, **anotherdict))

cukup sering terjadi dalam kode saya.

Awalnya dikirimkan oleh Alex Martelli

Catatan: Dalam Python 3, ini hanya akan berfungsi jika setiap kunci di basket_two adalah a string.

Tom Leys
sumber
3
Dokumentasi untuk dictmudah ditemukan sementara **sedikit lebih rumit (kata kunci kwargs ). Berikut ini penjelasan yang bagus: saltycrane.com/blog/2008/01/…
johndodo
4
ini dapat digunakan untuk menghasilkan variabel kedua dengan satu perintah, sedangkan basket_one.update(<dict>)seperti namanya, memperbarui kamus yang ada (atau yang dikloning).
Furins
2
Perhatikan bahwa dalam Python 3, nama argumen, dan dengan demikian kunci dari **anotherdict, harus berupa string.
Petr Viktorin
Terima kasih @johndodo - Saya telah mengintegrasikan saran Anda ke dalam pos.
Tom Leys
1
Alternatif fungsional yang bagus untuk jawaban yang diterima. Pendekatan ini diinginkan jika Anda perlu secara langsung menggunakan dikt yang baru digabungkan. (juga lihat komentar @ e18r pada jawaban yang diterima).
chinnychinchin
45

Sudahkah Anda mencoba menggunakan pemahaman kamus dengan pemetaan kamus:

a = {'a': 1, 'b': 2}
b = {'c': 3, 'd': 4}

c = {**a, **b}
# c = {"a": 1, "b": 2, "c": 3, "d": 4}

Cara lain untuk melakukannya adalah dengan Menggunakan dict (iterable, ** kwarg)

c = dict(a, **b)
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

Dalam Python 3.9 Anda dapat menambahkan dua dict menggunakan union | operator

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Vlad Bezden
sumber
5
FYI: ini bukan sintaks yang valid dalam Python 2.7
Asav Patel
2
Sintaks ini cukup baru (Python 3.5)
pianoJames
24
a.update(b)

Akan menambahkan kunci dan nilai dari b ke a , menimpa jika sudah ada nilai untuk kunci.

vartec
sumber
17

Seperti yang disebutkan orang lain, a.update(b)untuk beberapa dikte adan bakan mencapai hasil yang Anda minta dalam pertanyaan Anda. Namun, saya ingin menunjukkan bahwa berkali-kali saya telah melihat extendmetode pemetaan / set objek keinginan bahwa dalam sintaks a.extend(b), anilai-nilai TIDAK boleh ditimpa oleh bnilai-nilai. a.update(b)menimpa anilai-nilai, dan karenanya bukan pilihan yang baik untuk extend.

Perhatikan bahwa beberapa bahasa memanggil metode ini defaultsatau inject, karena dapat dianggap sebagai cara menyuntikkan nilai-nilai b (yang mungkin merupakan seperangkat nilai default) ke kamus tanpa menimpa nilai-nilai yang mungkin sudah ada.

Tentu saja, Anda dapat mencatat sederhana yang a.extend(b)hampir sama dengan b.update(a); a=b. Untuk menghapus tugas, Anda bisa melakukannya sebagai berikut:

def extend(a,b):
    """Create a new dictionary with a's properties extended by b,
    without overwriting.

    >>> extend({'a':1,'b':2},{'b':3,'c':4})
    {'a': 1, 'c': 4, 'b': 2}
    """
    return dict(b,**a)

Terima kasih kepada Tom Leys untuk ide cerdasnya yang menggunakan dictkonstruktor efek samping extend.

eblume
sumber
1

Anda juga dapat menggunakan koleksi python.Chainmap yang diperkenalkan dengan python 3.3.

from collections import Chainmap
c = Chainmap(a, b)
c['a'] # returns 1

Ini memiliki beberapa kemungkinan keuntungan, tergantung pada kasus penggunaan Anda. Mereka dijelaskan secara lebih rinci di sini , tetapi saya akan memberikan tinjauan singkat:

  • Chainmap hanya menggunakan tampilan kamus, jadi tidak ada data yang benar-benar disalin. Ini menghasilkan rantai yang lebih cepat (tapi pencarian lebih lambat)
  • Tidak ada kunci yang ditimpa jadi, jika perlu, Anda tahu apakah datanya berasal dari a atau b.

Ini terutama berguna untuk hal-hal seperti kamus konfigurasi.

Ivo Merchiers
sumber
0

Jika Anda membutuhkannya sebagai Kelas , Anda dapat memperluasnya dengan dict dan menggunakan metode pembaruan :

Class a(dict):
  # some stuff
  self.update(b)
Željko Šević
sumber