Je cherche un moyen de mettre à jour dict dictionary1 avec le contenu de la mise à jour de dict sans le niveau d'écrasementA
dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}
Je sais que la mise à jour supprime les valeurs du niveau 2 car elle met à jour le niveau de clé le plus bas1.
Comment pourrais-je m'y attaquer, étant donné que le dictionnaire1 et la mise à jour peuvent avoir n'importe quelle longueur?
Réponses:
La réponse de @ FM a la bonne idée générale, c'est-à-dire une solution récursive, mais un codage un peu particulier et au moins un bogue. Je recommanderais plutôt:
Python 2:
Python 3:
Le bug apparaît lorsque la « mise à jour » a un
k
,v
point oùv
estdict
etk
n'est pas à l' origine une clé dans le dictionnaire étant mis à jour - @ code « Les skips » FM cette partie de la mise à jour (parce qu'il ne se produit sur un vide nouvelledict
qui n'est pas enregistré ni retourné nulle part, juste perdu lorsque l'appel récursif revient).Mes autres changements sont mineurs: il n'y a aucune raison pour que la construction
if
/else
quand.get
effectue le même travail plus rapidement et plus proprement, etisinstance
est mieux appliquée aux classes de base abstraites (pas concrètes) pour la généralité.la source
isinstance
test, mais j'ai pensé que je tenterais d'y répondre.TypeError: 'int' object does not support item assignment.
lorsque vous, par exempleupdate({'k1': 1}, {'k1': {'k2': 2}})
. Pour modifier ce comportement et augmenter la profondeur des dictionnaires pour faire de la place pour des dictionnaires plus approfondis, vous pouvez ajouter unelif isinstance(d, Mapping):
autourd[k] = u[k]
de laisinstance
condition et après . Vous devrez également ajouter unelse: d = {k: u[k]}
pour traiter le cas où le dict de mise à jour est plus profond que le dict d'origine. Heureux de modifier la réponse, mais ne voulez pas salir de code concis qui résout le problème de l'OP.isinstance(v, collections.Mapping)
plutôt queisinstance(v, dict)
? Dans le cas où OP déciderait de commencer à utiliser des collections?u.iteritems()
enu.items()
, sinon vous rencontrerez:AttributeError: 'dict' object has no attribute 'iteritems'
Cela m'a pris un peu de temps sur celui-ci, mais grâce à la publication de @ Alex, il a comblé le vide qui me manquait. Cependant, je suis tombé sur un problème si une valeur dans le récursif
dict
se trouve être alist
, alors j'ai pensé partager et étendre sa réponse.la source
orig_dict.get(key, []) + val
.merged_tree = update({'default': {'initialvalue': 1}}, other_tree)
La réponse de @ Alex est bonne, mais ne fonctionne pas lors du remplacement d'un élément tel qu'un entier par un dictionnaire, tel que
update({'foo':0},{'foo':{'bar':1}})
. Cette mise à jour résout le problème:la source
elif
vérification du type d'objet d'origine une condition "englobante" contenant les vérifications à la fois de la valeur et de la clé de ce dict / mappage. Intelligent.update({'A1': 1, 'A2':2}, {'A1': {'B1': {'C1': 3, 'C2':4}, 'B2':2}, 'A3':5})
. Avez-vous un exemple qui ne fait pas ce que vous voulez?if isinstance(d, collections.Mapping)
sur chaque itération? Voyez ma réponse .Même solution que celle acceptée, mais nommage des variables plus claires, docstring et correction d'un bogue où
{}
une valeur ne remplaçait pas.Voici quelques cas de test:
Cette fonction est disponible dans le package charlatan , au format
charlatan.utils
.la source
Voici une version immuable de la fusion de dictionnaires récursive au cas où quelqu'un en aurait besoin.
Basé sur la réponse de @Alex Martelli .
Python 2.x:
Python 3.x:
la source
Améliorations mineures de la réponse de @ Alex qui permet de mettre à jour des dictionnaires de différentes profondeurs ainsi que de limiter la profondeur à laquelle la mise à jour plonge dans le dictionnaire imbriqué d'origine (mais la profondeur de mise à jour du dictionnaire n'est pas limitée). Seuls quelques cas ont été testés:
la source
update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})
j'ai ajouté une réponse qui résout ceif isinstance(d, Mapping)
sur chaque itération? Voyez ma réponse . (Aussi, je ne suis pas sûr de votred = {k: u[k]}
)Cette question est ancienne, mais j'ai atterri ici en cherchant une solution de "fusion profonde". Les réponses ci-dessus ont inspiré ce qui suit. J'ai fini par écrire le mien car il y avait des bugs dans toutes les versions que j'ai testées. Le point critique manqué était, à une certaine profondeur arbitraire des deux dicts d'entrée, pour une clé, k, l'arbre de décision lorsque d [k] ou u [k] n'est pas un dict était défectueux.
En outre, cette solution ne nécessite pas de récursivité, qui est plus symétrique avec la façon dont
dict.update()
fonctionne et retourneNone
.la source
Utilisez simplement
python-benedict
(je l'ai fait) , il a unemerge
méthode utilitaire (deepupdate) et bien d'autres. Cela fonctionne avec python 2 / python 3 et il est bien testé.Installation:
pip install python-benedict
Documentation: https://github.com/fabiocaccamo/python-benedict
la source
Dans aucune de ces réponses, les auteurs ne semblent comprendre le concept de mise à jour d'un objet stocké dans un dictionnaire ni même d'itération sur les éléments du dictionnaire (par opposition aux clés). J'ai donc dû en écrire un qui ne fasse pas de stockage et d'extraction de dictionnaires tautologiques inutiles. Les dictionnaires sont supposés stocker d'autres dictionnaires ou types simples.
Ou encore plus simple fonctionnant avec n'importe quel type:
la source
Mettez à jour la réponse de @Alex Martelli pour corriger un bogue dans son code afin de rendre la solution plus robuste:
La clé est que nous voulons souvent créer le même type à la récursivité, donc ici nous utilisons
v.copy().clear()
mais pas{}
. Et ceci est particulièrement utile si l'dict
ici est de typecollections.defaultdict
qui peut avoir différents types dedefault_factory
s.Notez également que le
u.iteritems()
a été changéu.items()
enPython3
.la source
J'ai utilisé la solution suggérée par @Alex Martelli, mais elle échoue
TypeError 'bool' object does not support item assignment
lorsque les deux dictionnaires diffèrent par le type de données à un certain niveau.
Dans le cas où au même niveau l'élément de dictionnaire
d
est juste un scalaire (c'est-à-dire.Bool
) Tandis que l'élément de dictionnaireu
est toujours dictionnaire, la réaffectation échoue car aucune affectation de dictionnaire n'est possible en scalaire (commeTrue[k]
).Une condition supplémentaire corrige que:
la source
Le code ci-dessous devrait résoudre le
update({'k1': 1}, {'k1': {'k2': 2}})
problème de la réponse de @Alex Martelli de la bonne manière.la source
utiliser
dict
oucollections.Mapping
la source
Je sais que cette question est assez ancienne, mais je poste toujours ce que je fais lorsque je dois mettre à jour un dictionnaire imbriqué. On peut utiliser le fait que les dicts sont passés par référence en python En supposant que le chemin de la clé est connu et séparé par des points. Forex si nous avons un dict nommé data:
Et nous voulons mettre à jour la classe de file d'attente, le chemin de la clé serait -
log_config_worker.handlers.queue.class
Nous pouvons utiliser la fonction suivante pour mettre à jour la valeur:
Cela mettrait à jour correctement le dictionnaire.
la source
Il se peut que vous tombiez sur un dictionnaire non standard, comme moi aujourd'hui, qui n'a pas d'itéritems-Attribute. Dans ce cas, il est facile d'interpréter ce type de dictionnaire comme un dictionnaire standard. Par exemple: Python 2.7:
Python 3.8:
la source
Oui! Et une autre solution. Ma solution diffère dans les clés qui sont vérifiées. Dans toutes les autres solutions, nous ne regardons que les clés
dict_b
. Mais ici, nous regardons dans l'union des deux dictionnaires.Faites-en ce que vous voulez
la source
Si vous souhaitez remplacer un "dictionnaire imbriqué complet par des tableaux", vous pouvez utiliser cet extrait de code:
Il remplacera toute "ancienne_valeur" par "nouvelle_valeur". Il s'agit en gros d'une reconstruction du dictionnaire en profondeur. Il peut même fonctionner avec List ou Str / int donné comme paramètre d'entrée du premier niveau.
la source
Une autre façon d'utiliser la récursivité:
la source
un nouveau Q comment Par un porte-clés
la source
vous pouvez essayer ceci, cela fonctionne avec des listes et est pur:
la source
Je recommande de remplacer
{}
partype(v)()
afin de propager le type d'objet de toute sous-classe de dict stockéeu
mais absente ded
. Par exemple, cela préserverait les types tels que les collections.Python 2:
Python 3:
la source
C'est un peu à l'écart mais avez-vous vraiment besoin de dictionnaires imbriqués? Selon le problème, un dictionnaire plat peut parfois suffire ... et le regarder bien:
la source
Si vous voulez un monoplace:
la source