Dans une réponse complémentaire, vous avez demandé quelle était la performance relative de ces deux alternatives :
z1 = dict(x.items() + y.items())
z2 = dict(x, **y)
Sur ma machine, en tout cas (un x86_64 assez ordinaire exécutant Python 2.5.2), l'alternative z2
est non seulement plus court et plus simple, mais aussi nettement plus rapide. Vous pouvez le vérifier par vous-même en utilisant le timeit
qui est fourni avec Python.
Exemple 1 : des dictionnaires identiques qui mettent en correspondance 20 entiers consécutifs avec 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
gagne par un facteur de 3,5 environ. Les différents dictionnaires semblent donner des résultats très différents, mais z2
semble toujours s'en sortir. (Si vous obtenez des résultats incohérents pour le même essayez de passer dans -r
avec un nombre plus grand que le 3 par défaut).
Exemple 2 : dictionnaires non chevauchants permettant de convertir 252 chaînes courtes en nombres 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
gagne par un facteur de 10 environ. C'est une grande victoire pour moi !
Après avoir comparé ces deux-là, je me suis demandé si z1
La mauvaise performance de l'entreprise pourrait être attribuée à la surcharge de la construction des deux listes d'items, ce qui m'a amené à me demander si cette variante pourrait mieux fonctionner :
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 z1
mais pas aussi rapide que z2
. Cela ne vaut vraiment pas la peine de faire tout ce travail d'écriture supplémentaire.
Il manque encore quelque chose d'important à cette discussion, à savoir une comparaison des performances de ces alternatives avec la méthode "évidente" de fusion de deux listes : l'utilisation de la fonction update
méthode. Pour essayer de garder les choses sur un pied d'égalité avec les expressions, dont aucune ne modifie x ou y, je vais faire une copie de x au lieu de le modifier en 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
y z2
semblent avoir des performances essentiellement identiques. Pensez-vous que cela puisse être une coïncidence ? Je ne....
En fait, je dirais même qu'il est impossible pour un code Python pur de faire mieux que cela. Et si vous pouvez faire beaucoup mieux dans un module d'extension C, j'imagine que les gens de Python pourraient bien être intéressés à incorporer votre code (ou une variation de votre approche) dans le noyau Python. Python utilise dict
dans beaucoup d'endroits ; l'optimisation de ses opérations est une affaire importante.
Vous pourriez également écrire ceci comme
z0 = x.copy()
z0.update(y)
comme le fait Tony, mais (sans surprise) la différence de notation s'avère ne pas avoir d'effet mesurable sur les performances. Utilisez celle qui vous semble la plus appropriée. Bien sûr, il a tout à fait raison de souligner que la version à deux énoncés est beaucoup plus facile à comprendre.
1 votes
Si vous voulez fusionner des espaces de noms (dicts en notation point), voyez ceci : stackoverflow.com/questions/56136549/
0 votes
La méthode d'implémentation choisie pour la méthode de mise à jour est déjà définie : la méthode change un attribut à l'intérieur de l'objet sans l'exposer à l'utilisateur, explicite (aka encapsulation). Ainsi vous pouvez implémenter une méthode pour retourner l'objet modifié directement à votre utilisation !