Bir sözlük için Python “genişletme”


465

Bir sözlüğü başka biriyle genişletmenin en iyi yolu hangisidir? Örneğin:

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

Bu kaçınarak fordöngü elde etmek için herhangi bir işlem arıyorum :

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

Gibi bir şey yapmak istiyorum:

a.extend(b)  # This does not work

25
Listeler için biliyordum [], sonra varsayalım değil, başkaları için çalışmak olabilir ;-)
FerranB

Yanıtlar:


697

6
Dokümanları okuduktan sonra neden bir 'güncelleme' var ama 'uzantı' yok.
georg

58
update () öğesinin doğrudan diktüyü değiştirdiğini ve Hiçbiri döndürmediğini unutmayın.
e18r

5
Yalnızca değerlerle dicti uzatmak istiyorsanız ne değil zaten tanımlı (yani varolan değerleri üzerine yazmasını değil)? Örneğin, bir dikteyi {"a":2, "b":3}dikte {"b":4, "c":5}etmek için dikte ile güncelle {"a":2, "b":3,"c":5}? Tabii ki update()bazı şeyleri hareket ettirerek kullanmak mümkündür , ancak sadece bir satırda gerçekleştirilebilseydi daha iyi olurdu ...
Nearoo

17
@Nearoo - tersini güncelleyin; x.update (y) [y ile x değerlerinin üzerine yazacak] yerine, y.update (x) [y değerlerini x ile değiştirir] kullanın ve sonraki işlemler için seçtiğiniz dikte olarak y'yi kullanın
jonathanl

updatesessizce mevcut girişlerin üzerine yazıldığını unutmayın . Yani, üst üste binen anahtarlar için olan değerlerin büzerine yazılır a.
CGFoX

187

Bu kapalı soruda güzel bir mücevher :

Girdi diklerinden hiçbirini değiştirmeyen "oneliner yolu"

basket = dict(basket_one, **basket_two)

Öğrenin **basket_two( **) burada demektir .

Bir çelişki olması durumunda, kaynağından gelen öğeler basket_twogeçersiz kılınacaktır basket_one. Tek gömlekler gittikçe, bu oldukça okunabilir ve şeffaftır ve diğer ikisinin bir karışımı olan bir dikte işe yaradığında her zaman kullanmaya karşı hiçbir fikrim yok (anlamakta zorlanan herhangi bir okuyucu aslında bunun kendisini öğrenmeye yöneltme biçimi dictve **;-). Örneğin, şöyle kullanır:

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

kodumda oldukça sık rastlanan olaylardır.

Orijinal Alex Martelli tarafından gönderildi

Not: Python 3'te, bu sadece basket_two'daki her anahtar a ise çalışır string.


3
İçin dokümantasyon dictbulmak **biraz daha zor (anahtar kelime kwargs ). İşte güzel bir açıklama: saltycrane.com/blog/2008/01/…
johndodo

4
bu, tek bir komutla ikinci bir değişken oluşturmak için kullanılabilirken basket_one.update(<dict>), adından da anlaşılacağı gibi, mevcut bir sözlüğü (veya klonlanmış olanı) günceller.
furins

2
Python 3'te, argüman adlarının ve dolayısıyla anahtarlarının **anotherdictdizeler olması gerektiğini unutmayın.
Petr Viktorin

Teşekkürler @johndodo - Önerilerinizi gönderiye entegre ettim.
Tom Leys

1
Kabul edilen cevaba güzel bir fonksiyonel alternatif. Yeni birleşik dikteyi doğrudan kullanmanız gerekiyorsa bu yaklaşım istenir. (ayrıca @ e18r'nin kabul edilen cevap hakkındaki yorumuna bakın).
chinnychinchin

45

Sözlük eşlemede sözlük anlama özelliğini kullanmayı denediniz mi:

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

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

Yapmanın başka bir yolu da dict kullanmaktır (yinelenebilir, ** kwarg)

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

Python 3.9'da birleşim kullanarak iki dikte ekleyebilirsiniz | Şebeke

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

5
Bilginize: Bu, Python 2.7'de geçerli bir sözdizimi değildir
Asav Patel

2
Bu sözdizimi oldukça yenidir (Python 3.5)
pianoJames

25
a.update(b)

Anahtarlarını ve değerlerini ekler misin b için bir zaten bir anahtar için değer varsa üzerine yazarak.


17

Diğerlerinin de belirttiği gibi, a.update(b)bazı zorluklar için ave bsorunuzda istediğiniz sonucu elde edeceksiniz. Ancak, birçok kez extendnesneleri eşleme / ayarlama yönteminin sözdiziminde a.extend(b), adeğerlerinin değerlerinin üzerine yazılmaması gerektiğine işaret ettiğimi belirtmek isterim b. değerlerinin a.update(b)üzerine yazar ave bunun için iyi bir seçim değildir extend.

Bazı dillerin bu yöntemi çağırdığını defaultsveya injectb'nin değerlerini (varsayılan değerler kümesi olabilir) zaten var olan değerlerin üzerine yazmadan bir sözlüğe enjekte etmenin bir yolu olarak düşünülebileceğini unutmayın.

Tabii ki, a.extend(b)neredeyse aynı olan basit bir not olabilir b.update(a); a=b. Ödevi kaldırmak için şu şekilde yapabilirsiniz:

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)

Tom Leys'e, yan etkisi olmayan bir dictkurucu kullanarak bu akıllı fikir için teşekkürler extend.


1

Python koleksiyonlarını da kullanabilirsiniz . Python 3.3'te tanıtılan bağlantı haritası.

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

Kullanım durumunuza bağlı olarak bunun birkaç olası avantajı vardır. Burada daha ayrıntılı olarak açıklanmaktadır , ancak kısa bir genel bakış sunacağım:

  • Bir zincir haritası yalnızca sözlüklerin görünümlerini kullanır, bu nedenle hiçbir veri kopyalanmaz. Bu daha hızlı zincirleme sağlar (ancak daha yavaş arama)
  • Aslında hiçbir anahtarın üzerine yazılmaz, bu nedenle gerekirse verilerin a veya b'den gelip gelmediğini bilirsiniz.

Bu temel olarak yapılandırma sözlükleri gibi şeyler için yararlı olur.


0

Bir Sınıf olarak ihtiyacınız olması durumunda , bunu dikte ile genişletebilir ve güncelleme yöntemini kullanabilirsiniz :

Class a(dict):
  # some stuff
  self.update(b)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.