Qual è la differenza tra dict () e {}?
-
21-08-2019 - |
Domanda
Quindi diciamo che voglio creare un dizionario. Lo chiameremo d
. Ma ci sono molti modi per inizializzare un dizionario in Python! Ad esempio, potrei farlo:
d = {'hash': 'bang', 'slash': 'dot'}
O potrei farlo:
d = dict(hash='bang', slash='dot')
O questo, curiosamente:
d = dict({'hash': 'bang', 'slash': 'dot'})
O questo:
d = dict([['hash', 'bang'], ['slash', 'dot']])
E tutta un'altra moltitudine di modi con la funzione dict()
. Quindi ovviamente una delle cose che d = {}
offre è la flessibilità nella sintassi e nell'inizializzazione. Ma non è quello che sto chiedendo.
Supponi che dovrei creare d = dict()
solo un dizionario vuoto. Cosa succede dietro le quinte dell'interprete Python quando faccio {}
contro <=>? Sono semplicemente due modi per fare la stessa cosa? L'uso di <=> ha la chiamata aggiuntiva di <=>? Uno ha (anche se trascurabile) più spese generali dell'altro? Mentre la domanda è davvero completamente irrilevante, è una curiosità a cui mi piacerebbe aver risposto.
Soluzione
>>> 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 () è apparentemente un C incorporato. Una persona davvero intelligente o dedicata (non io) potrebbe guardare la fonte dell'interprete e dirti di più. Volevo solo mostrare dis.dis. :)
Altri suggerimenti
Per quanto riguarda le prestazioni:
>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...
@Jacob: c'è una differenza nel modo in cui gli oggetti sono allocati, ma non sono copy-on-write. Python alloca un & Quot di dimensioni fisse; lista libera & Quot; dove può allocare rapidamente gli oggetti del dizionario (fino a quando non si riempie). I dizionari assegnati tramite la sintassi {}
(o una chiamata C a PyDict_New
) possono provenire da questo elenco gratuito. Quando il dizionario non fa più riferimento, viene restituito all'elenco libero e quel blocco di memoria può essere riutilizzato (anche se i campi vengono ripristinati per primi).
Questo primo dizionario viene immediatamente riportato all'elenco gratuito e il successivo riutilizzerà il suo spazio di memoria:
>>> id({})
340160
>>> id({1: 2})
340160
Se mantieni un riferimento, il prossimo dizionario verrà dal prossimo spazio libero:
>>> x = {}
>>> id(x)
340160
>>> id({})
340016
Ma possiamo eliminare il riferimento a quel dizionario e liberare di nuovo il suo slot:
>>> del x
>>> id({})
340160
Poiché la sintassi dict()
è gestita in codice byte, può utilizzare questa ottimizzazione sopra menzionata. D'altra parte, <=> viene gestito come un normale costruttore di classi e Python utilizza l'allocatore di memoria generico, che non segue uno schema facilmente prevedibile come l'elenco libero sopra.
Inoltre, guardando compile.c da Python 2.6, con la sintassi <=> sembra pre-dimensionare la tabella hash in base al numero di elementi che sta memorizzando che è noto al momento dell'analisi.
Fondamentalmente, {} è sintassi ed è gestito a livello di lingua e bytecode. dict () è solo un altro builtin con una sintassi di inizializzazione più flessibile. Nota che dict () è stato aggiunto solo nel mezzo della serie 2.x.
Aggiorna : grazie per le risposte. Rimossa la speculazione su copia su scrittura.
Un'altra differenza tra {}
e dict
è che <=> alloca sempre un nuovo dizionario (anche se i contenuti sono statici) mentre <=> non sempre ( vedi la risposta di mgood per quando e perché):
def dict1():
return {'a':'b'}
def dict2():
return dict(a='b')
print id(dict1()), id(dict1())
print id(dict2()), id(dict2())
produce:
$ ./mumble.py 11642752 11642752 11867168 11867456
Non sto suggerendo di provare a trarre vantaggio da questo o no, dipende dalla situazione particolare, basta sottolinearlo. (Probabilmente è anche evidente dal smontaggio se si capisce il codici operativi).
dict () viene utilizzato quando si desidera creare un dizionario da un iterabile, come:
dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )
Uso divertente:
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)
uscita:
I want to be printed
a
Per creare un set vuoto dovremmo usare il set di parole chiave prima di esso
vale a dire set()
questo crea un set vuoto dove come in dicts solo le parentesi di fiori possono creare un dict vuoto
Andiamo con un esempio
print isinstance({},dict)
True
print isinstance({},set)
False
print isinstance(set(),set)
True