Python "erweitern" für ein Wörterbuch


463

Was ist der beste Weg, um ein Wörterbuch um ein anderes zu erweitern? Zum Beispiel:

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

Ich suche nach einer Operation, um diese Vermeidungsschleife zu erhalten for:

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

Ich möchte etwas tun wie:

a.extend(b)  # This does not work

25
Ich wusste für Listen [], dann nehme ich an, dass Arbeit für andere sein kann, nicht extrange ;-)
FerranB

Antworten:


695

6
Nach dem Lesen der Dokumentation wird man verstehen, warum es ein "Update" gibt, aber kein "Extend".
Georg

58
Beachten Sie, dass update () das Diktat direkt ändert und None zurückgibt.
e18r

5
Was aber, wenn Sie das Diktat nur um Werte erweitern möchten, die noch nicht definiert sind (dh vorhandene Werte nicht überschreiben)? Zum Beispiel ein Diktat {"a":2, "b":3}mit Diktat {"b":4, "c":5}zu Diktat aktualisieren {"a":2, "b":3,"c":5}? Natürlich ist es möglich, update()einige
Dinge zu

17
@Nearoo - einfach umgekehrt aktualisieren; Verwenden Sie anstelle von x.update (y) [das x-Werte mit y überschreiben würde] y.update (x) [das y-Werte mit x überschreibt] und verwenden Sie y als Ihr ausgewähltes Diktat für weitere Operationen
jonathanl

Beachten Sie, dass updatevorhandene Einträge stillschweigend überschrieben werden. Das heißt, alle Werte in büberschreiben die Werte afür überlappende Schlüssel.
CGFoX

186

Ein schönes Juwel in dieser geschlossenen Frage :

Der "Oneliner-Weg", der keine der Eingabediktate ändert, ist

basket = dict(basket_one, **basket_two)

Erfahren Sie hier, was **basket_two(das **) bedeutet .

Im Konfliktfall basket_twoüberschreiben die Elemente von die Elemente von basket_one. Als Einzeiler ist dies ziemlich lesbar und transparent, und ich habe keine Möglichkeit, es zu verwenden, wenn ein Diktat, das eine Mischung aus zwei anderen ist, nützlich ist (jeder Leser, der Schwierigkeiten hat, es zu verstehen, wird tatsächlich sehr gut bedient die Art und Weise, wie dies ihn oder sie zum Lernen anregt dictund die **Form ;-). So verwendet zum Beispiel:

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

sind ziemlich häufig in meinem Code.

Ursprünglich eingereicht von Alex Martelli

Hinweis: In Python 3 funktioniert dies nur, wenn jeder Schlüssel in bask_two a ist string.


3
Die Dokumentation für dictist leicht zu finden, während sie **etwas kniffliger ist (Schlüsselwort ist kwargs ). Hier ist eine schöne Erklärung: saltycrane.com/blog/2008/01/…
Johndodo

4
Dies kann verwendet werden, um eine zweite Variable mit einem einzigen Befehl zu generieren, während, basket_one.update(<dict>)wie der Name schon sagt, ein vorhandenes Wörterbuch (oder ein geklontes) aktualisiert wird.
Furins

2
Beachten Sie, dass in Python 3 Argumentnamen und damit die Schlüssel von **anotherdictZeichenfolgen sein müssen.
Petr Viktorin

Danke @johndodo - Ich habe deine Vorschläge in den Beitrag integriert.
Tom Leys

1
Eine schöne funktionale Alternative zur akzeptierten Antwort. Dieser Ansatz ist wünschenswert, wenn Sie das neu kombinierte Diktat direkt verwenden müssen. (Siehe auch den Kommentar von @ e18r zur akzeptierten Antwort).
Chinnychinchin

45

Haben Sie versucht, das Wörterbuchverständnis mit der Wörterbuchzuordnung zu verwenden:

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

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

Eine andere Möglichkeit ist die Verwendung von dict (iterable, ** kwarg).

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

In Python 3.9 können Sie mit union | zwei Diktate hinzufügen Operator

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


2
Diese Syntax ist ziemlich neu (Python 3.5)
pianoJames

24
a.update(b)

Fügt Schlüssel und Werte von b zu a hinzu und überschreibt sie, wenn bereits ein Wert für einen Schlüssel vorhanden ist.


17

Wie andere erwähnt haben, a.update(b)für einige dicts aund berreichen wird das Ergebnis , das Sie in Ihrer Frage gestellt haben. Ich möchte jedoch darauf hinweisen , dass viele Male habe ich das gesehen extendVerfahren zum Abbilden / set Objekte wünschen , dass in der Syntax a.extend(b), a‚s - Werte sollten nicht durch sein überschrieben bs Werte‘. a.update(b)überschreibt adie Werte und ist daher keine gute Wahl für extend.

Beachten Sie, dass einige Sprachen diese Methode aufrufen defaultsoder inject, da dies als eine Möglichkeit zum Einfügen von b-Werten (bei denen es sich möglicherweise um eine Reihe von Standardwerten handelt) in ein Wörterbuch eingefügt werden kann, ohne möglicherweise bereits vorhandene Werte zu überschreiben.

Natürlich könnte man einfach feststellen, dass dies a.extend(b)fast dasselbe ist wie b.update(a); a=b. Um die Zuordnung zu entfernen, können Sie dies folgendermaßen tun:

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)

Vielen Dank an Tom Leys für diese clevere Idee mit einem dictKonstruktor ohne Nebenwirkungen für extend.


1

Sie können auch die Python- Sammlungen verwenden. Chainmap, die in Python 3.3 eingeführt wurde.

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

Dies hat je nach Anwendungsfall einige mögliche Vorteile. Sie werden hier näher erläutert , aber ich werde einen kurzen Überblick geben:

  • Eine Kettenkarte verwendet nur Ansichten der Wörterbücher, sodass tatsächlich keine Daten kopiert werden. Dies führt zu einer schnelleren Verkettung (aber einer langsameren Suche).
  • Es werden keine Schlüssel überschrieben, sodass Sie bei Bedarf wissen, ob die Daten von a oder b stammen.

Dies macht es hauptsächlich für Dinge wie Konfigurationswörterbücher nützlich.


0

Falls Sie es als Klasse benötigen , können Sie es mit dict erweitern und die Aktualisierungsmethode verwenden:

Class a(dict):
  # some stuff
  self.update(b)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.