Ich suche nach einer Möglichkeit, dict dictionary1 mit dem Inhalt von dict update zu aktualisieren, ohne LevelA zu überschreiben
dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}
Ich weiß, dass das Update die Werte in Level2 löscht, weil es die niedrigste Schlüsselebene1 aktualisiert.
Wie könnte ich das angehen, da Wörterbuch1 und Update beliebig lang sein können?
Antworten:
Die Antwort von @ FM hat die richtige allgemeine Idee, dh eine rekursive Lösung, aber etwas eigenartige Codierung und mindestens einen Fehler. Ich würde stattdessen empfehlen:
Python 2:
Python 3:
Der Fehler zeigt sich , wenn die „update“ hat einen
k
,v
Punkt , wov
adict
undk
ist nicht ursprünglich ein Schlüssel im Wörterbuch aktualisiert - @ FM Code „überspringt“ dieser Teil des Updates (weil er es auf einen leeren neuen führtdict
die wird nirgendwo gespeichert oder zurückgegeben, sondern geht nur verloren, wenn der rekursive Aufruf zurückkehrt.Meine anderen Änderungen sind geringfügig: Es gibt keinen Grund für das Konstrukt
if
/else
, wenn.get
derselbe Job schneller und sauberer ausgeführt wird, und es wird aus Gründen derisinstance
Allgemeinheit am besten auf abstrakte Basisklassen (keine konkreten) angewendet.quelle
isinstance
Test umzugehen, dachte aber, ich würde es versuchen.TypeError: 'int' object does not support item assignment.
wenn Sie zupdate({'k1': 1}, {'k1': {'k2': 2}})
. Um dieses Verhalten zu ändern und stattdessen die Tiefe der Wörterbücher zu erweitern, um Platz für tiefere Wörterbücher zu schaffen, können Sie einelif isinstance(d, Mapping):
umd[k] = u[k]
und nach derisinstance
Bedingung hinzufügen . Sie müssen auch ein hinzufügenelse: d = {k: u[k]}
, um den Fall zu behandeln, dass das Aktualisierungsdiktat tiefer liegt als das ursprüngliche Diktat. Gerne bearbeiten wir die Antwort, möchten aber keinen prägnanten Code verschmutzen, der das Problem des OP löst.isinstance(v, collections.Mapping)
eher verwenden alsisinstance(v, dict)
? Für den Fall, dass OP beschließt, Sammlungen zu verwenden?u.iteritems()
aufu.items()
, sonst werden Sie feststellen:AttributeError: 'dict' object has no attribute 'iteritems'
Ich habe ein bisschen gebraucht, aber dank @ Alex 'Post hat er die Lücke gefüllt, die mir gefehlt hat. Ich bin jedoch auf ein Problem gestoßen, wenn ein Wert innerhalb des Rekursiven
dict
zufällig ein istlist
, und ich dachte, ich würde ihn teilen und seine Antwort erweitern.quelle
orig_dict.get(key, []) + val
.merged_tree = update({'default': {'initialvalue': 1}}, other_tree)
Die Antwort von @ Alex ist gut, funktioniert aber nicht, wenn ein Element wie eine Ganzzahl durch ein Wörterbuch wie z
update({'foo':0},{'foo':{'bar':1}})
. Dieses Update behebt es:quelle
elif
Überprüfung des ursprünglichen Objekttyps zu einer "einschließenden" Bedingung gemacht, die die Überprüfung sowohl des Werts als auch des Schlüssels dieses Diktats / dieser Zuordnung enthält. Klug.update({'A1': 1, 'A2':2}, {'A1': {'B1': {'C1': 3, 'C2':4}, 'B2':2}, 'A3':5})
. Haben Sie ein Beispiel, das nicht das tut, was Sie wollen?if isinstance(d, collections.Mapping)
bei jeder Iteration testen ? Siehe meine Antwort .Dieselbe Lösung wie die akzeptierte, aber klarere Benennung der Variablen, Dokumentzeichenfolge und Behebung eines Fehlers, bei
{}
dem ein Wert nicht überschrieben wird.Hier einige Testfälle:
Diese Funktion ist im charlatan- Paket in verfügbar
charlatan.utils
.quelle
Hier ist eine unveränderliche Version der rekursiven Wörterbuchzusammenführung, falls jemand sie benötigt.
Basierend auf der Antwort von @Alex Martelli .
Python 2.x:
Python 3.x:
quelle
Kleinere Verbesserungen an der Antwort von @ Alex, die das Aktualisieren von Wörterbüchern unterschiedlicher Tiefe sowie das Begrenzen der Tiefe ermöglicht, in die das Update in das ursprünglich verschachtelte Wörterbuch eintaucht (die Aktualisierungstiefe des Wörterbuchs ist jedoch nicht begrenzt). Es wurden nur wenige Fälle getestet:
quelle
update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})
Ich habe eine Antwort hinzugefügt, die dies ansprichtif isinstance(d, Mapping)
bei jeder Iteration testen ? Siehe meine Antwort . (Ich bin mir auch nicht sicherd = {k: u[k]}
)Diese Frage ist alt, aber ich bin hier gelandet, als ich nach einer "Deep Merge" -Lösung gesucht habe. Die obigen Antworten haben das Folgende inspiriert. Am Ende habe ich meine eigenen geschrieben, weil es in allen von mir getesteten Versionen Fehler gab. Der kritische Punkt, der übersehen wurde, war, dass in einer beliebigen Tiefe der beiden Eingabediktate für einen Schlüssel k der Entscheidungsbaum, wenn d [k] oder u [k] kein Diktat ist, fehlerhaft war.
Außerdem erfordert diese Lösung keine Rekursion, die symmetrischer zur Funktionsweise
dict.update()
ist, und kehrt zurückNone
.quelle
Verwenden Sie einfach
python-benedict
(ich habe es getan) , es hat einemerge
(Deepupdate-) Dienstprogrammmethode und viele andere. Es funktioniert mit Python 2 / Python 3 und ist gut getestet.Installation:
pip install python-benedict
Dokumentation: https://github.com/fabiocaccamo/python-benedict
quelle
In keiner dieser Antworten scheinen die Autoren das Konzept zu verstehen, ein in einem Wörterbuch gespeichertes Objekt zu aktualisieren oder sogar über Wörterbuchelemente zu iterieren (im Gegensatz zu Schlüsseln). Also musste ich eine schreiben, die keine sinnlosen tautologischen Wörterbuchspeicher und -abrufe macht. Es wird angenommen, dass die Diktate andere Diktate oder einfache Typen speichern.
Oder noch einfacher, wenn man mit einem beliebigen Typ arbeitet:
quelle
Aktualisieren Sie die Antwort von @Alex Martelli, um einen Fehler in seinem Code zu beheben und die Lösung robuster zu machen:
Der Schlüssel ist, dass wir bei der Rekursion oft denselben Typ erstellen möchten , also verwenden wir hier
v.copy().clear()
aber nicht{}
. Und dies ist besonders nützlich, wenn dasdict
hier vom Typcollections.defaultdict
ist, der verschiedene Arten vondefault_factory
s haben kann.Beachten Sie auch, dass das
u.iteritems()
in in geändertu.items()
wurdePython3
.quelle
Ich habe die von @Alex Martelli vorgeschlagene Lösung verwendet, aber sie schlägt fehl
TypeError 'bool' object does not support item assignment
wenn sich die beiden Wörterbücher auf einer bestimmten Ebene im Datentyp unterscheiden.
Wenn auf derselben Ebene das Element des Wörterbuchs
d
nur ein Skalar ist (dhBool
), während das Element des Wörterbuchsu
noch ein Wörterbuch ist, schlägt die Neuzuweisung fehl, da keine Wörterbuchzuweisung in den Skalar (wieTrue[k]
) möglich ist.Eine zusätzliche Bedingung behebt Folgendes:
quelle
Der folgende Code sollte das
update({'k1': 1}, {'k1': {'k2': 2}})
Problem in der Antwort von @Alex Martelli richtig lösen .quelle
benutze
dict
odercollections.Mapping
quelle
Ich weiß, dass diese Frage ziemlich alt ist, poste aber immer noch, was ich mache, wenn ich ein verschachteltes Wörterbuch aktualisieren muss. Wir können die Tatsache verwenden, dass Diktate in Python als Referenz übergeben werden. Angenommen, der Pfad des Schlüssels ist bekannt und durch Punkte getrennt. Forex, wenn wir ein Diktat mit dem Namen data haben:
Und wir wollen die Warteschlangenklasse aktualisieren, der Pfad des Schlüssels wäre -
log_config_worker.handlers.queue.class
Wir können die folgende Funktion verwenden, um den Wert zu aktualisieren:
Dies würde das Wörterbuch korrekt aktualisieren.
quelle
Es könnte sein, dass Sie über ein Nicht-Standard-Wörterbuch wie mich heute stolpern, das kein iteritems-Attribut hat. In diesem Fall ist es einfach, diese Art von Wörterbuch als Standardwörterbuch zu interpretieren. Beispiel: Python 2.7:
Python 3.8:
quelle
Ja! Und noch eine Lösung. Meine Lösung unterscheidet sich in den Schlüsseln, die überprüft werden. Bei allen anderen Lösungen sehen wir uns nur die Schlüssel an
dict_b
. Aber hier schauen wir in die Vereinigung beider Wörterbücher.Mach damit, wie du willst
quelle
Wenn Sie ein "vollständig verschachteltes Wörterbuch durch Arrays" ersetzen möchten, können Sie dieses Snippet verwenden:
Es wird jeden "alten_Wert" durch "neuen_Wert" ersetzen. Es wird ungefähr eine tiefgreifende Neuerstellung des Wörterbuchs durchgeführt. Es kann sogar mit List oder Str / int als Eingabeparameter der ersten Ebene arbeiten.
quelle
Eine andere Möglichkeit, die Rekursion zu verwenden:
quelle
ein neues Q wie man durch eine Schlüsselkette
quelle
Sie könnten dies versuchen, es funktioniert mit Listen und ist rein:
quelle
Ich empfehle,
{}
durch zu ersetzentype(v)()
, um den Objekttyp einer Dikt-Unterklasse zu verbreiten, die in gespeichert ist,u
aber nicht vorhanden istd
. Dies würde beispielsweise Typen wie Sammlungen beibehalten. OrderedDict:Python 2:
Python 3:
quelle
Das ist ein bisschen zur Seite, aber brauchen Sie wirklich verschachtelte Wörterbücher? Je nach Problem kann manchmal ein flaches Wörterbuch ausreichen ... und gut aussehen:
quelle
Wenn Sie einen Einzeiler wollen:
quelle