update - python merge dictionaries with same keys




Wie verschmelzen zwei Wörterbücher in einem Ausdruck? (20)

Ich habe zwei Python-Wörterbücher, und ich möchte einen einzigen Ausdruck schreiben, der diese beiden Wörterbücher zusammenführt. Die update() -Methode wäre das, was ich brauche, wenn sie ihr Ergebnis zurückliefert, anstatt ein Diktat an Ort und Stelle zu ändern.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

Wie kann ich das letzte zusammengesetzte Diktat in z , nicht in x ?

(Um es noch deutlicher zu machen, ist es das, was ich mit dem Konfliktbewältigen von dict.update() letzter dict.update() habe.


Wie kann ich zwei Python-Wörterbücher in einem Ausdruck zusammenführen?

Für die Wörterbücher x und y wird z zu einem flach zusammengeführten Wörterbuch, wobei Werte von y diejenigen von x ersetzen.

  • In Python 3.5 oder höher:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • In Python 2 (oder 3.4 oder niedriger) schreibe eine Funktion:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z
    

    und nun:

    z = merge_two_dicts(x, y)
    

Erläuterung

Angenommen, Sie haben zwei Diktate und möchten diese zu einem neuen Diktat zusammenfügen, ohne die ursprünglichen Diktate zu ändern:

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

Das gewünschte Ergebnis besteht darin, ein neues Wörterbuch ( z ) mit den zusammengeführten Werten zu erhalten, und die Werte des zweiten Diktiers überschreiben diese aus dem ersten.

>>> z
{'a': 1, 'b': 3, 'c': 4}

Eine neue, hierfür in PEP 448 vorgeschlagene und ab Python 3.5 verfügbare Syntax ist

z = {**x, **y}

Und es ist tatsächlich ein einzelner Ausdruck.

Beachten Sie, dass wir uns auch mit der wörtlichen Notation verbinden können:

z = x.copy()
z.update(y) # which returns None since it mutates z

und nun:

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

Es wird nun so angezeigt, wie es im Release-Zeitplan für 3.5, PEP 478 , implementiert ist, und es hat nun seinen Weg in das Was ist neu in Python 3.5- Dokument gefunden.

Da sich jedoch viele Organisationen noch auf Python 2 befinden, möchten Sie dies möglicherweise auf abwärtskompatible Weise tun. Der klassische Pythonic-Weg, der in Python 2 und Python 3.0-3.4 verfügbar ist, besteht darin, diesen Prozess in zwei Schritten auszuführen:

z = merge_two_dicts(x, y)

In beiden Ansätzen kommt y an zweiter Stelle und seine Werte werden die Werte von x ersetzen, daher wird 'b' in unserem Endergebnis auf 3 .

Noch nicht auf Python 3.5, möchte aber einen einzelnen Ausdruck

Wenn Sie noch nicht mit Python 3.5 arbeiten oder abwärtskompatiblen Code schreiben müssen und dies in einem einzigen Ausdruck möchten, ist der performanteste, wenn auch korrekte Ansatz die Verwendung einer Funktion:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

und dann hast du einen einzigen Ausdruck:

z = merge_dicts(a, b, c, d, e, f, g) 

Sie können auch eine Funktion erstellen, um eine undefinierte Anzahl von Diktaten von Null bis zu einer sehr großen Anzahl zusammenzuführen:

z = dict(x.items() + y.items())

Diese Funktion funktioniert in Python 2 und 3 für alle Diktate. zB gegebene Wörter a bis g :

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

und Schlüsselwertpaare in g haben Vorrang vor den Diagrammen a bis f und so weiter.

Kritiken anderer Antworten

Verwenden Sie nicht das, was Sie in der früher akzeptierten Antwort sehen:

>>> c = dict(a.items() | b.items())

In Python 2 erstellen Sie zwei Listen im Speicher für jedes Diktat, erstellen eine dritte Liste im Speicher mit einer Länge, die der Länge der ersten beiden zusammengesetzt ist, und verwerfen Sie dann alle drei Listen, um das Diktat zu erstellen. In Python 3 dict_items dies fehl, weil Sie zwei dict_items Objekte zusammen hinzufügen, nicht zwei Listen.

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

und Sie müssten sie explizit als Listen erstellen, zB z = dict(list(x.items()) + list(y.items())) . Dies ist eine Verschwendung von Ressourcen und Rechenleistung.

In ähnlicher Weise viewitems() die Vereinigung von items() in Python 3 ( viewitems() in Python 2.7) fehl, wenn es sich bei Werten um nicht-verschiebbare Objekte handelt (wie z. B. Listen). Selbst wenn Ihre Werte hashierbar sind, da Mengen semantisch ungeordnet sind, ist das Verhalten hinsichtlich der Rangfolge nicht definiert. Also mach das nicht:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

Dieses Beispiel zeigt, was passiert, wenn Werte nicht unverschiebbar sind:

z = dict(x, **y)

Hier ist ein Beispiel, bei dem y Vorrang haben sollte. Stattdessen wird der Wert von x aufgrund der willkürlichen Reihenfolge der Mengen beibehalten:

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Ein weiterer Hack, den Sie nicht verwenden sollten:

dict(a=1, b=10, c=11)

Dies verwendet den dict Konstruktor und ist sehr schnell und speichereffizient (sogar etwas mehr als unser zweistufiger Prozess). Wenn Sie jedoch nicht genau wissen, was hier passiert, wird das zweite Diktat als Schlüsselwortargument an das übergeben Diktorkonstruktor), es ist schwer zu lesen, es ist nicht die beabsichtigte Verwendung und daher nicht Pythonic.

Hier ist ein Beispiel für die Verwendung in Django .

Diktiere sollen Hash-Schlüssel annehmen (z. B. Frozensets oder Tupel), aber diese Methode schlägt in Python 3 fehl, wenn Schlüssel keine Zeichenfolgen sind.

{'a': 1, 'b': 10, 'c': 11}

Guido van Rossum, der Schöpfer der Sprache, schrieb aus der Mailingliste :

Ich bin gut darin, Diktale ({}, ** {1: 3}) für illegal zu erklären, da es ja ein Missbrauch des ** Mechanismus ist.

und

Anscheinend geht dict (x, ** y) als "cooler Hack" für "x.update (y) aufrufen und x zurückgeben". Ich persönlich finde es eher verachtenswert als cool.

Ich verstehe (ebenso wie das Verständnis des Erstellers der Sprache ), dass die beabsichtigte Verwendung für dict(**y) das Erstellen von Diktaten für Lesbarkeitszwecke ist, zB:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

anstatt

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

Antwort auf Kommentare

Ungeachtet dessen, was Guido sagt, entspricht dict(x, **y) der Diktospezifikation, die übrigens. funktioniert sowohl für Python 2 als auch für 3. Python 2 und 3. Die Tatsache, dass dies nur für String-Schlüssel funktioniert, ist eine direkte Folge der Funktionsweise von Schlüsselwortparametern und nicht eines Kurzbefehls von dict. Die Verwendung des ** -Operators an dieser Stelle ist auch kein Missbrauch des Mechanismus. In der Tat war ** genau darauf ausgelegt, Diktate als Schlüsselwörter zu übergeben.

Wieder funktioniert es nicht für 3, wenn Schlüssel keine Zeichenfolgen sind. Der implizite Aufrufvertrag besagt, dass Namespaces gewöhnliche Diktate annehmen, während Benutzer nur Schlüsselwortargumente übergeben müssen, die Zeichenfolgen sind. Alle anderen Callables haben es erzwungen. dict diese Konsistenz in Python 2 gebrochen:

dict((k, v) for d in dicts for k, v in d.items())

Diese Inkonsistenz war bei anderen Implementierungen von Python (Pypy, Jython, IronPython) schlecht. Daher wurde es in Python 3 behoben, da diese Verwendung eine grundlegende Änderung darstellen kann.

Ich sage Ihnen, es sei böswillige Inkompetenz, absichtlich Code zu schreiben, der nur in einer Version einer Sprache oder nur unter bestimmten willkürlichen Einschränkungen funktioniert.

Mehr Kommentare:

dict(x.items() + y.items()) ist immer noch die dict(x.items() + y.items()) Lösung für Python 2. Die Lesbarkeit zählt.

Meine Antwort: merge_two_dicts(x, y) scheint mir viel klarer zu sein, wenn uns die Lesbarkeit wirklich wichtig ist. Und es ist nicht vorwärtskompatibel, da Python 2 zunehmend veraltet ist.

{**x, **y} scheint keine verschachtelten Wörterbücher zu verarbeiten. Der Inhalt verschachtelter Schlüssel wird einfach überschrieben, nicht zusammengeführt [...]. Ich wurde durch diese Antworten verbrannt, die nicht rekursiv miteinander verschmelzen, und ich war überrascht, dass es niemand erwähnt hat. In meiner Interpretation des Wortes "verschmelzen" beschreiben diese Antworten "das Aktualisieren eines Diktiers mit einem anderen" und nicht das Verschmelzen.

Ja. Ich muss Sie zurück auf die Frage verweisen, die nach einer flachen Verschmelzung von zwei Wörterbüchern verlangt, wobei die Werte des ersten durch den zweiten überschrieben werden - in einem einzigen Ausdruck.

Angenommen, zwei Wörterbücher für Wörterbücher werden möglicherweise rekursiv in einer einzigen Funktion zusammengeführt. Sie sollten jedoch darauf achten, dass die Wörter nicht von beiden Quellen geändert werden. Die sicherste Möglichkeit, dies zu vermeiden, besteht darin, beim Zuweisen von Werten eine Kopie zu erstellen. Da Schlüssel hashable sein müssen und daher normalerweise unveränderlich sind, ist es sinnlos, sie zu kopieren:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Verwendungszweck:

import timeit

Das Aufkommen von Eventualitäten für andere Werttypen geht weit über den Rahmen dieser Frage hinaus, daher möchte ich Sie auf meine Antwort auf die kanonische Frage zu einem "Wörterbücher der Wörterbücher zusammenführen" hinweisen.

Weniger performant, aber korrekte Ad-hocs

Diese Ansätze sind weniger performant, liefern jedoch korrektes Verhalten. Sie sind viel weniger performant als copy und update oder das neue Auspacken, da sie jedes Schlüsselwertpaar auf einer höheren Abstraktionsebene durchlaufen, aber sie respektieren die Rangfolge (letzteres hat Vorrang).

Sie können die Diktate auch manuell innerhalb eines Diktierverstehens verketten:

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

oder in Python 2.6 (und vielleicht bereits 2.4, wenn Generatorausdrücke eingeführt wurden):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

itertools.chain die Iteratoren in der richtigen Reihenfolge über die Schlüssel-Wert-Paare:

z = dict(x.items() + y.items())

Leistungsüberprüfung

Ich werde nur die Leistungsanalyse der Verwendungen durchführen, von denen bekannt ist, dass sie sich korrekt verhalten.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Folgendes wird auf Ubuntu 14.04 ausgeführt

In Python 2.7 (System Python):

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

In Python 3.5 (Deadsnakes PPA):

z = x.copy()
z.update(y)

Ressourcen zu Wörterbüchern


Rekursives / tiefes Update eines Diktats

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Demonstration:

final = {'a': 1, 'b': 1, **x, **y}

Ausgänge:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

Vielen Dank für die Änderungen.


Dies wird wahrscheinlich keine beliebte Antwort sein, aber Sie möchten dies höchstwahrscheinlich nicht. Wenn Sie eine Kopie wünschen, die eine Zusammenführung ist, verwenden Sie copy (oder deepcopy , je nachdem, was Sie möchten) und aktualisieren Sie dann. Die zwei Codezeilen sind viel besser lesbar - mehr Pythonic - als die einzeilige Erstellung mit .items () + .items (). Explicit ist besser als implizit.

Wenn Sie .items () (vor Python 3.0) verwenden, erstellen Sie außerdem eine neue Liste, die die Elemente aus dem Diktat enthält. Wenn Ihre Wörterbücher groß sind, ist das ziemlich viel Aufwand (zwei große Listen, die verworfen werden, sobald das zusammengeführte Diktat erstellt wird). update () kann effizienter arbeiten, da es das zweite Dikt für Element durchlaufen kann.

In time Hinsicht:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

Die winzige Verlangsamung zwischen den ersten beiden ist es meiner Meinung nach für die Lesbarkeit wert. Darüber hinaus wurden Schlüsselwortargumente für die Wörterbucherstellung nur in Python 2.3 hinzugefügt, wohingegen copy () und update () in älteren Versionen funktionieren.


Eine Alternative:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

Einfache Lösung mit itertools, die die Ordnung beibehält (letztere Diktate haben Vorrang)

import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}

r = dict(collections.ChainMap(a, b, c))
print(r)

Und es ist Verwendung:

{1: 1, 2: 2, 3: 4}

Ich wollte etwas Ähnliches, aber mit der Möglichkeit, anzugeben, wie die Werte für doppelte Schlüssel zusammengeführt wurden, habe ich dies herausgehackt (aber nicht ausgiebig getestet). Offensichtlich ist dies kein einzelner Ausdruck, sondern ein einzelner Funktionsaufruf.

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

In Python 3 können Sie collections.ChainMap die mehrere Diktiere oder andere Zuordnungen zu einer einzelnen, aktualisierbaren Ansicht zusammenfasst:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

In einer Folgeantwort haben Sie nach der relativen Leistung dieser beiden Alternativen gefragt:

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

Zumindest auf meinem Rechner (einem ziemlich gewöhnlichen x86_64 mit Python 2.5.2) ist alternative z2 nicht nur kürzer und einfacher, sondern auch wesentlich schneller. Sie können dies mit dem in Python enthaltenen timeit Modul selbst überprüfen.

Beispiel 1: identische Wörterbücher, die sich 20 aufeinander folgende Ganzzahlen zuordnen:

z0 = dict(x)
z0.update(y)

z2 gewinnt mit einem Faktor von z2 3,5. Unterschiedliche Wörterbücher scheinen recht unterschiedliche Ergebnisse zu liefern, aber z2 scheint immer die z2 vorn zu haben. (Wenn Sie für den gleichen Test inkonsistente Ergebnisse erhalten, geben Sie -r mit einer Zahl ein, die größer als der Standardwert 3 ist.)

Beispiel 2: Nicht überlappende Wörterbücher, die 252 kurze Zeichenfolgen in Ganzzahlen abbilden und umgekehrt:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

z2 gewinnt etwa um den Faktor 10. Das ist ein ziemlich großer Gewinn in meinem Buch!

Nachdem ich die beiden verglichen hatte, fragte ich mich, ob die schlechte Leistung von z1 auf den Aufwand beim Erstellen der beiden Artikellisten zurückzuführen ist, was mich zu der Frage veranlasste, ob diese Variante besser funktioniert:

z0 = x.copy()
z0.update(y)

Einige schnelle Tests, z

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

Ich z3 zu dem Schluss, dass z3 etwas schneller ist als z1 , aber nicht annähernd so schnell wie z2 . Auf jeden Fall das zusätzliche Tippen nicht wert.

Dieser Diskussion fehlt noch etwas Wichtiges, nämlich ein Leistungsvergleich dieser Alternativen mit der "offensichtlichen" Art, zwei Listen zusammenzuführen: mit der update . Um zu versuchen, die Dinge auf eine Stufe mit den Ausdrücken zu stellen, von denen keiner x oder y modifiziert, werde ich eine Kopie von x erstellen, anstatt sie wie folgt zu verändern:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11

Ein typisches Ergebnis:

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

Mit anderen Worten scheinen z0 und z0 eine im Wesentlichen identische Leistung zu haben. Denken Sie, dass dies ein Zufall sein könnte? Ich nicht....

Ich würde sogar so weit gehen und behaupten, dass reiner Python-Code nichts Besseres leisten kann. Und wenn Sie mit einem C-Erweiterungsmodul wesentlich bessere Ergebnisse erzielen können, sind die Python-Leute wahrscheinlich daran interessiert, Ihren Code (oder eine Variation Ihres Ansatzes) in den Python-Kern zu integrieren. Python verwendet dict an vielen Stellen. Die Optimierung der Abläufe ist eine große Sache.

Sie könnten dies auch als schreiben

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

wie Tony, aber (nicht überraschend) hat sich herausgestellt, dass der Unterschied in der Notation keinen messbaren Einfluss auf die Leistung hat. Verwenden Sie, was für Sie richtig aussieht. Natürlich ist es absolut richtig, darauf hinzuweisen, dass die Version mit zwei Anweisungen viel einfacher zu verstehen ist.


Missbrauch führt zu einer Ein-Ausdruck-Lösung für Matthews Antwort :

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

Sie sagten, Sie wollten einen Ausdruck, also habe ich lambda missbraucht, um einen Namen zu binden, und Tupel, um die Grenze von Lambdas Ausdrücken zu überschreiben. Fühlen Sie sich frei, sich zusammenzucken.

Sie können dies natürlich auch tun, wenn Sie nicht daran interessiert sind, es zu kopieren:

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

Python 3.5 (PEP 448) ermöglicht eine schönere Syntaxoption:

def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Oder auch

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

Während die Frage bereits mehrmals beantwortet wurde, wurde diese einfache Lösung des Problems noch nicht aufgelistet.

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

Es ist so schnell wie z0 und das oben erwähnte böse z2, aber leicht zu verstehen und zu ändern.


Wenn Sie denken, dass Lambdas böse sind, lesen Sie nicht weiter. Auf Wunsch können Sie die schnelle und speichereffiziente Lösung mit einem Ausdruck schreiben:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Wie oben vorgeschlagen, ist die Verwendung von zwei Zeilen oder das Schreiben einer Funktion wahrscheinlich der bessere Weg.



Das Problem, das ich bei den bisher aufgelisteten Lösungen habe, ist, dass im zusammengeführten Wörterbuch der Wert für Schlüssel "b" 10 ist, aber meiner Meinung nach sollte es 12 sein. In diesem Licht stelle ich Folgendes vor:

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

Ergebnisse:

dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}

Für Python 2:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}

Für Python 3:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

Es gibt Ausgabe: {'a': 1, 'c': 11, 'b': 10}


Ich habe hier und anderswo auf Ideen gestützt und habe eine Funktion verstanden:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}

Verwendung (getestet in Python 3):

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

Sie könnten stattdessen ein Lambda verwenden.


In Python 3.5 können Sie Unpack **verwenden, um ein neues Wörterbuch zu erstellen. Diese Methode wurde in früheren Antworten nicht gezeigt. Es ist auch besser, {}statt zu verwenden dict(). Weil {}ist ein Python-Literal und dict()beinhaltet einen Funktionsaufruf.

 dict1 = {'a':1} dict2 = {'b':2} new_dict = {**dict1, **dict2} >>>new_dict {'a':1, 'a':2} 

Obwohl die Antworten für dieses flache Wörterbuch gut waren, führt keine der hier definierten Methoden tatsächlich eine tiefe Wörterbuchzusammenführung durch.

Beispiele folgen:

{'two': True, 'one': {'extra': False}}

Man würde ein Ergebnis von so etwas erwarten:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()+y.items())
print(z)

Stattdessen bekommen wir das:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()|y.items())
print(z)

Der Eintrag "one" hätte "depth_2" und "extra" als Elemente in seinem Wörterbuch, wenn es wirklich eine Zusammenführung war.

Die Kette funktioniert auch nicht:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Ergebnisse in:

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

Die tiefe Verschmelzung, die rcwesick hervorbrachte, führt auch zu demselben Ergebnis.

Ja, es wird funktionieren, um die Beispielwörterbücher zusammenzuführen, aber keines von ihnen ist ein allgemeiner Mechanismus zum Zusammenführen. Ich werde das später aktualisieren, sobald ich eine Methode schreibe, die eine echte Zusammenführung durchführt.


from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}

Unter diesen zwielichtigen und zweifelhaften Antworten ist dieses leuchtende Beispiel der einzige gute Weg, um Diktaturen in Python zusammenzuführen, die vom Diktator für das Leben von Guido van Rossum selbst befürwortet werden! Jemand anderes schlug die Hälfte davon vor, legte es aber nicht in eine Funktion.

dict(x.items() | y.items())

gibt:

dict(x.viewitems() | y.viewitems())




merge