248 votes

Y a-t-il une différence entre l'utilisation d'un dict littéral et d'un dict constructeur ?

En utilisant PyCharm, j'ai remarqué qu'il propose de convertir un fichier dictée littérale :

d = {
    'one': '1',
    'two': '2',
}

en un Constructeur dict :

d = dict(one='1', two='2')

Ces différentes approches diffèrent-elles de manière significative ?

(En rédigeant cette question, j'ai remarqué que l'utilisation de dict() il semble impossible de spécifier une touche numérique d = {1: 'one', 2: 'two'} est possible, mais, évidemment, dict(1='one' ...) ne l'est pas. Autre chose ?)

9 votes

dict() prend une liste de paires clé-valeur et autorise les paramètres nommés. Il peut donc être utilisé pour créer n'importe quel type de dict, mais pas avec la syntaxe que vous utilisez. Il est également important de noter qu'il y a eu un bug ( youtrack.jetbrains.net/issue/PY-2512 ) dans pyCharm spécifiquement à cause de ce que vous avez découvert, qui a été corrigé).

1 votes

Liés : stackoverflow.com/questions/5790860/ (résumé : le comportement de PyCharm est plus lent et plus moche)

1 votes

Apparemment, CPython 2.7 dict() est plus lent (6 fois plus lent ?). Voir : doughellmann.com/2012/11/ De toute façon, je commence à préférer la syntaxe des constructeurs, car je trouve plus facile de taper et de déplacer le code entre les dicts et les appels de fonction.

138voto

gnibbler Points 103484

Je pense que vous avez mis en évidence la différence la plus évidente. A part cela,

le premier n'a pas besoin de chercher dict ce qui devrait le rendre un peu plus rapide

le second lève les yeux dict en locals() et ensuite globals() et le trouve le builtin, donc vous pouvez changer le comportement en définissant un local appelé dict par exemple, même si je ne vois pas où ce serait une bonne idée, à part peut-être lors du débogage.

4 votes

Un exemple de cas où un local appelé dict pourrait être utile : stackoverflow.com/a/7880276/313113

0 votes

Je pense que l'utilisation de dict() va d'abord construire un dict pour les arguments de dict() et ensuite créer un second dict pour l'instance de dict à créer. Braces crée l'instance de dict en une seule étape.

1 votes

dict pourrait être combiné avec zip pour convertir deux tableaux parallèles (c'est-à-dire liés) en un seul mappage d'association.

78voto

Daniel Kluev Points 4321

Literal est beaucoup plus rapide, car il utilise des opcodes BUILD_MAP et STORE_MAP optimisés plutôt que le générique CALL_FUNCTION :

> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop

> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop

> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop

> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop

11 votes

Ned : La plupart du temps, pour la plupart des utilisateurs, cela n'a aucune importance, mais il y a des situations où des millions ou des milliards de ces fichiers sont créés et où une accélération de 2 fois est significative.

5 votes

@MrFooz : il y a des situations comme ça. Je pense que vous constaterez que 99,9 % des personnes qui font des micro-chronométrages ne se trouvent pas dans ces situations.

31 votes

@Ned C'est pertinent dans un fil de discussion demandant lequel est le plus rapide.

41voto

Paolo Moretti Points 9519

Ils sont à peu près les mêmes sous Python 3.2.

Comme gnibbler l'a fait remarquer, le premier n'a pas besoin de rechercher dict ce qui devrait le rendre un peu plus rapide.

>>> def literal():
...   d = {'one': 1, 'two': 2}
...
>>> def constructor():
...   d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 ('one')
              9 STORE_MAP
             10 LOAD_CONST               3 (2)
             13 LOAD_CONST               4 ('two')
             16 STORE_MAP
             17 STORE_FAST               0 (d)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE
>>> dis.dis(constructor)
  2           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('one')
              6 LOAD_CONST               2 ('1')
              9 LOAD_CONST               3 ('two')
             12 LOAD_CONST               4 ('2')
             15 CALL_FUNCTION          512
             18 STORE_FAST               0 (d)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

1 votes

Notez que dans certaines implémentations, ce n'est pas vraiment un "tout petit peu", mais plutôt un facteur de 100 : $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' "{'a': 1, 'b': 2, 'c': 3}" ....... Mean +- std dev: 1.73 ns +- 0.14 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' '{k:v for k,v in i}' ....... Mean +- std dev: 139 ns +- 10 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' 'dict(i)' ....... Mean +- std dev: 188 ns +- 16 ns

14voto

Ned Batchelder Points 128913

Ces deux approches produisent des dictionnaires identiques, sauf, comme vous l'avez noté, lorsque les règles lexicales de Python interfèrent.

Les littéraux de dictionnaire sont un peu plus évidents que les dictionnaires, et vous pouvez créer n'importe quel type de clé, mais vous devez citer les noms des clés. D'autre part, vous pouvez utiliser des variables pour les clés si vous en avez besoin pour une raison quelconque :

a = "hello"
d = {
    a: 'hi'
    }

El dict() vous donne plus de flexibilité en raison de la variété des formes d'entrée qu'il accepte. Par exemple, vous pouvez lui fournir un itérateur de paires, et il les traitera comme des paires clé/valeur.

Je n'ai aucune idée de la raison pour laquelle PyCharm propose de convertir une forme en l'autre.

2 votes

Eh bien, je suppose que PyCharm essaie juste d'être très gentil. Tout comme il semble toujours proposer de convertir les chaînes de caractères à guillemets simples en chaînes de caractères à guillemets doubles, sans raison apparente.

1 votes

Vous n'avez besoin de citer vos clés que si vos clés sont des chaînes de caractères. Elles pourraient tout aussi bien être des tuples de frozensets de floats, bien que cela puisse devenir un peu laid.

7voto

Artsiom Rudzenka Points 9771

Extrait du tutoriel python 2.7 :

Une paire d'accolades crée un vide : {}. En plaçant une liste de paires clé:valeur séparées par des virgules séparée par des virgules à l'intérieur des accolades ajoute les paires paires clé:valeur initiales au dictionnaire ; c'est également de cette manière que les dictionnaires sont écrits sur la sortie.

tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}

Alors que :

Le constructeur dict() construit des directement à partir de listes de paires clé-valeur stockées sous forme de tuples. Lorsque les paires forment un motif, la liste peuvent spécifier de manière compacte la liste de valeurs-clés.

tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))

Lorsque les clés sont de simples chaînes de caractères, il est parfois plus facile de spécifier des paires en utilisant des arguments de type mot-clé :

dict(sape=4139, guido=4127, jack=4098)
>>>  {'sape': 4139, 'jack':4098, 'guido': 4127}

Ainsi, {} et dict() produisent tous deux des dictionnaires mais fournissent des méthodes légèrement différentes d'initialisation des données de dictionnaire.

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:

X