Quelle est la différence entre dict () et {}?
-
21-08-2019 - |
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.
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