2009-03-19 5 views
49

Alors disons que je veux faire un dictionnaire. Nous l'appellerons d. Mais il y a plusieurs façons d'initialiser un dictionnaire en Python! Par exemple, je pourrais le faire:Quelle est la différence entre dict() et {}?

d = {'hash': 'bang', 'slash': 'dot'} 

Ou je pouvais faire:

d = dict(hash='bang', slash='dot') 

Ou cela, curieusement:

d = dict({'hash': 'bang', 'slash': 'dot'}) 

Ou ceci:

d = dict([['hash', 'bang'], ['slash', 'dot']]) 

Et toute une multitude de façons avec le dict() fonction. Donc, évidemment, l'une des choses que fournit dict() est la flexibilité dans la syntaxe et l'initialisation. Mais ce n'est pas ce que je demande.

dire que je devais faire d juste un dictionnaire vide. Que se passe-t-il dans les coulisses de l'interpréteur Python quand je fais d = {} par rapport à d = dict()? Est-ce simplement deux façons de faire la même chose? Est-ce que l'utilisation {} a l' appel supplémentaire de dict()? L'un a-t-il (même négligeable) plus de frais généraux que l'autre? Alors que la question est vraiment sans importance, c'est une curiosité que j'aurais aimé avoir.

+0

J'ai trouvé le lot d'explication plus claire ici: https://doughellmann.com/blog/2012/11/12/the-performance-impact-of -using-dict-of-in-cpython-2-7-2/ – theBuzzyCoder

Répondre

61
>>> def f(): 
...  return {'a' : 1, 'b' : 2} 
... 
>>> def g(): 
...  return dict(a=1, b=2) 
... 
>>> g() 
{'a': 1, 'b': 2} 
>>> f() 
{'a': 1, 'b': 2} 
>>> import dis 
>>> dis.dis(f) 
    2   0 BUILD_MAP    0 
       3 DUP_TOP    
       4 LOAD_CONST    1 ('a') 
       7 LOAD_CONST    2 (1) 
      10 ROT_THREE   
      11 STORE_SUBSCR   
      12 DUP_TOP    
      13 LOAD_CONST    3 ('b') 
      16 LOAD_CONST    4 (2) 
      19 ROT_THREE   
      20 STORE_SUBSCR   
      21 RETURN_VALUE   
>>> dis.dis(g) 
    2   0 LOAD_GLOBAL    0 (dict) 
       3 LOAD_CONST    1 ('a') 
       6 LOAD_CONST    2 (1) 
       9 LOAD_CONST    3 ('b') 
      12 LOAD_CONST    4 (2) 
      15 CALL_FUNCTION   512 
      18 RETURN_VALUE   

dict() est apparemment une partie de C intégrée. Une personne vraiment intelligente ou dévouée (pas moi) pourrait regarder la source de l'interprète et vous en dire plus. Je voulais juste montrer dis.dis. :)

+1

Malheureusement personne ne pourrait vous dire ce qui se cache derrière 'g' à cause de' CALL_FUNCTION 512' ... –

+2

Jetez un oeil à cet article de Doug Hellmann: http://doughellmann.com/2012/11/12/the-performance-impact-of-using-dict-instead-of-in-cpython-2-7-2.html – ezdazuzena

+1

Nouveau python a fait ' {'a': 1, 'b': 2} 'plus efficace. par exemple. en python 2.7.10, le désassemblage remplace le 'ROT_THREE; STORE_SUBSCR; Instructions DUP_TOP' avec 'STORE_MAP'. En python 3.5.1, il se débarrasse de tous et n'a qu'un seul 'BUILD_MAP'. – danio

31

En ce qui concerne la performance va:

>>> from timeit import timeit 
>>> timeit("a = {'a': 1, 'b': 2}") 
0.424... 
>>> timeit("a = dict(a = 1, b = 2)") 
0.889... 
+0

J'obtiens un résultat similaire pour le dictionnaire vide: 0.1usec pour 'x = {}' vs 0.3usec pour 'x = dict()'. –

+0

Ouais; les appels de fonction sont chers. Mais cette forme est plus polyvalente, c'est à dire dict (zip ( – DNS

+0

exactement.) Les appels de fonctions sont environ 80-100 fois plus cher en Python, que dans C. – vartec

8

Fondamentalement, {} est la syntaxe et est géré au niveau de langue et bytecode. dict() est juste un autre builtin avec une syntaxe d'initialisation plus flexible. Notez que dict() n'a été ajouté qu'au milieu de la série 2.x.

5

Mise à jour: Merci pour les réponses. Suppression des spéculations sur la copie sur écriture.

Une autre différence entre {} et dict est que dict toujours un nouveau alloue dictionnaire (même si le contenu est statique) alors que {} ne le fait pas toujours faire (voir mgood's answer quand et pourquoi):

def dict1(): 
    return {'a':'b'} 

def dict2(): 
    return dict(a='b') 

print id(dict1()), id(dict1()) 
print id(dict2()), id(dict2()) 

produit:

 
$ ./mumble.py 
11642752 11642752 
11867168 11867456 

Je ne suggère pas que vous essayez de tirer parti de ce ou non, il DEPE nds sur la situation particulière, juste le signaler. (C'est aussi probablement évident à partir du disassembly si vous comprenez les opcodes).

+2

Ce n'est pas ce qui se passe ici. {} alloue toujours un nouveau dict (sinon ce serait très mauvais), mais le fait que vous ne le gardiez pas en vie signifie que l'id peut être réutilisé après sa mort (dès que le premier dict est imprimé). – Brian

+0

Je soupçonne que l'appel de la fonction agit différemment parce qu'il remue un peu plus l'espace id() de sorte qu'un identifiant différent est obtenu lors du second appel. – Brian

+0

Je pense que la réponse de mgood a clarifié les choses; J'ai mis à jour mon entrée. –

24

@Jacob: Il y a une différence dans la façon dont les objets sont attribués, mais ils ne sont pas copy-on-write. Python alloue une "liste libre" de taille fixe où il peut rapidement allouer des objets de dictionnaire (jusqu'à ce qu'il se remplisse). Les dictionnaires attribués via la syntaxe {} (ou un appel C vers PyDict_New) peuvent provenir de cette liste libre.Lorsque le dictionnaire n'est plus référencé, il est renvoyé à la liste libre et ce bloc de mémoire peut être réutilisé (bien que les champs soient d'abord réinitialisés).

Ce premier dictionnaire obtient immédiatement retourné à la liste libre, et la prochaine réutilisera son espace mémoire:

>>> id({}) 
340160 
>>> id({1: 2}) 
340160 

Si vous gardez une référence, le dictionnaire prochain viendra de la prochaine fente libre:

>>> x = {} 
>>> id(x) 
340160 
>>> id({}) 
340016 

Mais nous pouvons supprimer la référence à ce dictionnaire et à nouveau libre son emplacement:

>>> del x 
>>> id({}) 
340160 

Puisque la syntaxe {} est gérée en byte-code, elle peut utiliser cette optimisation mentionnée ci-dessus. D'autre part, dict() est géré comme un constructeur de classe normal et Python utilise l'allocateur de mémoire générique, qui ne suit pas un modèle facilement prévisible comme la liste libre ci-dessus. De plus, en regardant compile.c à partir de Python 2.6, avec la syntaxe {}, il semble de pré-dimensionner la hashtable en fonction du nombre d'éléments stockés qui sont connus au moment de l'analyse.

3

dict() est utilisée lorsque vous souhaitez créer un dictionnaire à partir d'un itératives, comme:

dict(generator which yields (key,value) pairs) 
dict(list of (key,value) pairs) 
+1

Oui. Et les cas qui peuvent utiliser '{...}' à la place devraient le faire parce qu'il est plus direct et plus rapide qu'un appel au constructeur 'dict()' (les appels de fonction sont chers, en Python, et pourquoi appeler une fonction qui retourne seulement quelque chose qui peut être construit directement via la syntaxe '{...}'?). – EOL

+0

Je crois que {...} ne fonctionne que dans python3 – peufeu

+0

Il fonctionne depuis longtemps en Python 2. – EOL

-1

Pour créer un ensemble vide nous devrions utiliser le mot-clé mis en avant qu'il -à-dire set() cela crée une ensemble vide où, comme dans dicts que les supports de fleurs peuvent créer un dict vide

Permet de passer par un exemple

print isinstance({},dict) 
True 
print isinstance({},set) 
False 
print isinstance(set(),set) 
True 
0

utilisation drôle:

def func(**kwargs): 
     for e in kwargs: 
     print(e) 
    a = 'I want to be printed' 
    kwargs={a:True} 
    func(**kwargs) 
    a = 'I dont want to be printed' 
    kwargs=dict(a=True) 
    func(**kwargs) 

sortie:

I want to be printed 
a 
+1

Je ne sais pas si vous voulez dire drôle comme dans 'lol' ou drôle comme dans 'bug'. S'il vous plaît inclure une sorte de commentaire ou d'explication à ce que cette question a été répondue il y a 8 ans, et cela va laisser noobs dans une certaine mesure perplexe –

Questions connexes