4443 votes

Comment puis-je les fusionner (union), les deux dictionnaires Python dans une expression unique?

J'ai deux dictionnaires Python, et je veux écrire une seule expression qui renvoie ces deux dictionnaires, ont fusionné. La méthode update() est ce dont j'ai besoin, si il est rentré de son résultat au lieu de modifier un dict en place.

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

Donc, je veux que final fusionné dict à z, pas de x. Comment puis-je faire cela?

(Pour être plus clair, la dernière-et-un-victoires de gestion des conflits d' dict.update() est ce que je cherche).

1575voto

Thomas Vander Stichele Points 16872

Dans votre cas, ce que vous pouvez faire est:

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

Ce sera, comme vous le voulez, mettre la dernière dict en z, et la valeur de b être correctement remplacée par la seconde (y) dict:

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

Si vous utilisez Python 3, il est seulement un peu plus compliqué. Pour créer z:

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

615voto

Matthew Schinckel Points 15596

Une alternative:

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

327voto

Carl Meyer Points 30736

Un autre, plus concis, option:

z = dict(x, **y)

Remarque: il est devenu un populaire réponse, mais il est important de souligner que, si y a tout non-clés de chaîne, le fait que cela fonctionne à tous est un abus de Disponible détail d'implémentation, et il ne fonctionne pas dans Disponible 3.2, ou dans PyPy, IronPython, ou Jython. Aussi, Guido n'est pas un fan. Donc je ne peux pas recommander cette technique pour compatible ou de la croix-de la mise en œuvre du code portable, ce qui signifie qu'il doit être entièrement évité.

204voto

Tony Meyer Points 4700

Ce ne sera probablement pas une réponse, mais vous avez presque certainement ne voulez pas le faire. Si vous voulez une copie d'une fusion, puis utiliser la copie (ou propriétédeepcopy, selon ce que vous voulez), puis mise à jour. Les deux lignes de code beaucoup plus lisible plus Pythonic - de la création de la ligne à .les éléments() + .les éléments(). Explicite est mieux qu'implicites.

En outre, lorsque vous utilisez .les éléments() (pré Python 3.0), vous êtes en train de créer une nouvelle liste qui contient les éléments de la dict. Si votre dictionnaires sont grandes, alors que c'est beaucoup de frais généraux (deux grandes listes qui seront jetés dès que la fusion dict est créé). mise à jour() peuvent travailler plus efficacement, car il peut courir à travers la deuxième dict de l'élément par élément.

En termes de temps:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO le petit ralentissement entre les deux premiers est-il la peine pour la lisibilité. En outre, les arguments mots-clefs pour créer un dictionnaire n'a été ajouté en Python 2.3, tandis que la copie() et update() va travailler dans les anciennes versions.

141voto

zaphod Points 1980

Carl, un suivi de la réponse, vous avez demandé à propos de la performance relative de ces deux alternatives:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

Sur ma machine, au moins assez ordinaire x86_64 lancer Python 2.5.2), la variante z2 n'est pas seulement plus rapide et plus simple, mais aussi beaucoup plus rapide. Vous pouvez le vérifier par vous-même à l'aide de l' timeit module est livré avec Python.

Exemple 1: identique dictionnaires cartographie 20 nombres entiers consécutifs à eux-mêmes

% 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

z2 victoires par un facteur de 3,5 ou. Les différents dictionnaires paraît donner des résultats assez différents, mais z2 semble toujours aller de l'avant. (Si vous obtenez des résultats incohérents pour le même test, essayer de passer en -r avec un nombre de plus que la valeur par défaut de 3.)

Exemple 2: le non-chevauchement des dictionnaires de cartographie 252 chaînes courtes pour les entiers et vice versa

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 victoires par un facteur d'environ 10. C'est une assez grande victoire, dans mon livre!

Après avoir comparé ces deux, je me demandais si z1s'mauvaise performance pourrait être attribuée à la surcharge de construction de deux listes d'objets, qui à son tour m'a conduit à me demander si cette variation pourrait fonctionner mieux:

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

Quelques tests rapides, par exemple

% 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

m'amènent à conclure que z3 est un peu plus rapide que d' z1, mais pas aussi vite que z2. Certainement pas la peine tout le taper.

Cette discussion est toujours manquer quelque chose d'important, qui est une comparaison des performances de ces solutions de rechange avec le "évident" voie de la fusion de deux listes: l'utilisation de l' update méthode. Pour essayer de garder les choses sur un pied d'égalité avec les expressions, aucune de modifier x ou y, je vais faire une copie de x au lieu de le modifier sur place, comme suit:

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

Un résultat typique:

% 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

En d'autres termes, z0 et z2 semblent avoir essentiellement des performances identiques. Pensez-vous que cela pourrait être une coïncidence? Je n'ai pas....

En fait, j'irais même jusqu'à prétendre qu'il est impossible pour un pur code Python pour faire mieux que cela. Et si vous pouvez faire nettement mieux dans un C module d'extension, j'imagine que le Python de gens pourrait bien être intéressé par l'incorporation de votre code (ou une variation sur votre approche) dans le Python de base. Python utilise dict dans beaucoup d'endroits; l'optimisation de ses opérations est une grosse affaire.

[Mise à JOUR: Vous pouvez également écrire ce que

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

comme Tony, mais (sans surprise) la différence de notation s'avère n'avoir aucun effet mesurable sur la performance. Utilisation selon la regarde droit pour vous. Bien sûr, il a tout à fait raison de souligner que les deux-déclaration de version est beaucoup plus facile à comprendre.]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: