Question

Alors disons que je veux faire un dictionnaire. Nous l'appellerons d. Mais il existe plusieurs façons d’initialiser un dictionnaire en Python! Par exemple, je pourrais faire ceci:

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

Ou je pourrais faire ceci:

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

Ou ceci, curieusement:

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

Ou ceci:

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

Et une multitude d'autres façons d'utiliser la fonction dict(). De manière évidente, l’un des éléments fournis par d = {} est la souplesse de la syntaxe et de l’initialisation. Mais ce n’est pas ce que je demande.

Disons que je devais faire d = dict() juste un dictionnaire vide. Que se passe-t-il dans les coulisses de l'interpréteur Python lorsque je fais {} contre <=>? Est-ce simplement deux façons de faire la même chose? L'utilisation de <=> entraîne-t-elle l'appel supplémentaire de <=>? L’un at-il (même négligeable) plus de frais généraux que l’autre? Même si la question n’a vraiment aucune importance, c’est une curiosité que j’aurais bien voulu répondre.

Était-ce utile?

La solution

>>> 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 du C intégré. Une personne très intelligente ou dévouée (pas moi) pourrait consulter la source de l’interprète et vous en dire plus. Je voulais juste montrer dis.dis. :)

Autres conseils

En ce qui concerne les performances:

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

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

Ce premier dictionnaire est immédiatement ramené à la liste libre et le prochain réutilisera son espace mémoire:

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

Si vous conservez une référence, le prochain dictionnaire proviendra du prochain emplacement libre:

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

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

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

Comme la dict() syntaxe est gérée en octet-code, elle peut utiliser l'optimisation mentionnée ci-dessus. Par contre, <=> est traité comme un constructeur de classe ordinaire et Python utilise l’allocateur de mémoire générique, qui ne suit pas un modèle facilement prévisible comme celui de la liste libre ci-dessus.

En outre, si vous regardez compile.c à partir de Python 2.6, avec la <=> syntaxe, il semble que le hashtable prédéfinit le hashtable en fonction du nombre d'éléments qu'il stocke, ce qui est connu au moment de l'analyse.

Fondamentalement, {} est une syntaxe et est géré au niveau du langage et du bytecode. dict () est juste un autre construit avec une syntaxe d'initialisation plus flexible. Notez que dict () n’a été ajouté qu’au milieu des séries 2.x.

Mise à jour : merci pour les réponses. Suppression de la spéculation sur la copie sur écriture.

Une autre différence entre {} et dict est que <=> attribue toujours un nouveau dictionnaire (même si le contenu est statique) alors que <=> ne le fait pas toujours ( voir la réponse de mgood pour 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 essayiez de tirer profit de ceci ou non, cela dépend de la situation particulière, soulignez simplement. (Cela ressort probablement aussi du désassemblage si vous comprenez la opcodes).

dict () est utilisé lorsque vous voulez créer un dictionnaire à partir d'un itératif, tel que:

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

Utilisation amusante:

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

Afin de créer un ensemble vide, nous devrions utiliser le mot-clé avant c.-à-d. set() cela crée un ensemble vide où, comme dans les dessins, seuls les crochets de fleurs peuvent créer un dict vide

Partons avec un exemple

print isinstance({},dict) 
True 
print isinstance({},set) 
False 
print isinstance(set(),set) 
True
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top