[] e {} vs list () e dict (), quale è meglio?


113

Capisco che siano entrambi essenzialmente la stessa cosa, ma in termini di stile, qual è il migliore (più Pythonic) da usare per creare un elenco o un dict vuoto?

Risposte:


197

In termini di velocità, non c'è concorrenza per elenchi / dict vuoti:

>>> from timeit import timeit
>>> timeit("[]")
0.040084982867934334
>>> timeit("list()")
0.17704233359267718
>>> timeit("{}")
0.033620194745424214
>>> timeit("dict()")
0.1821558326547077

e per non vuoti:

>>> timeit("[1,2,3]")
0.24316302770330367
>>> timeit("list((1,2,3))")
0.44744206316727286
>>> timeit("list(foo)", setup="foo=(1,2,3)")
0.446036018543964
>>> timeit("{'a':1, 'b':2, 'c':3}")
0.20868602015059423
>>> timeit("dict(a=1, b=2, c=3)")
0.47635635255323905
>>> timeit("dict(bar)", setup="bar=[('a', 1), ('b', 2), ('c', 3)]")
0.9028228448029267

Inoltre, l'uso della notazione tra parentesi ti consente di utilizzare la comprensione di elenchi e dizionari, il che potrebbe essere un motivo sufficiente.


4
Anche la comprensione di dettami e liste può essere eseguita utilizzando i nomi inglesi. Esempio:list(i for i in range(10) if i % 2)
Zags

4
c'è un motivo per cui {} e [] sono molto più veloci? Pensavo fossero semplicemente degli alias.
Justin D.

Il tempo non sembra dare un tempo preciso. Secondo il benchmark, sembra che ci voglia ~ 200 ms, che è molto più lento delle normali chiamate http. Prova a eseguire dict () normalmente nella shell e quindi esegui timeit ("dict ()"), vedrai una differenza visibile nell'esecuzione.
piyush

2
@piyush In realtà, la timeit()funzione riporta la quantità di tempo totale per eseguire un numero specificato di iterazioni, che è 1000000per impostazione predefinita. Quindi gli esempi sopra sono il numero di secondi per eseguire lo snippet di codice un milione di volte. Ad esempio timeit('dict()', number=1) // -> 4.0531158447265625e-06(un'iterazione) mentre timeit('dict()') // -> 0.12412905693054199(un milione di iterazioni)
Greg Haskins

@GregHaskins quindi in quel caso, non vedo che ci si dovrebbe preoccupare di usare dict () o {}, a meno che non si ripetano un milione di record e si utilizzi dict () nel ciclo.
piyush

37

Secondo me []e {}sono i modi più pitonici e leggibili per creare elenchi / dict vuoti.

Fai attenzione set()però, ad esempio:

this_set = {5}
some_other_set = {}

Può creare confusione. Il primo crea un set con un elemento, il secondo crea un dict vuoto e non un set.


4
{}crea sempre un dict vuoto. {1,2,3}crea un set in 2.7+ ma è un errore di sintassi nelle 2.6versioni precedenti e.
ThiefMaster

1
spiacente? è una variabile con un nome some_epic_setche punta a un dictoggetto vuoto ... non è un insieme vuoto. Per un set vuoto è necessario utilizzare set().
6502

2
@ 6502: In effetti, ma è una trappola comune che {5}crea un insieme con un elemento 5ed {}è un dict vuoto.
orlp

1
Wow, questo è stato fonte di confusione. Tuttavia, non è il livello di confusione Fractal of Bad Design. :-)
Prof. Falken

4
@EnderLook: In realtà, con la decompressione generalizzata , puoi usare {*()}per creare un vuoto setcon sintassi letterale. Lo chiamo l'operatore scimmia con un occhio solo. :-)
ShadowRanger

17

Il letterale dict potrebbe essere un piccolo po 'più veloce come il suo bytecode è più breve:

In [1]: import dis
In [2]: a = lambda: {}
In [3]: b = lambda: dict()

In [4]: dis.dis(a)
  1           0 BUILD_MAP                0
              3 RETURN_VALUE

In [5]: dis.dis(b)
  1           0 LOAD_GLOBAL              0 (dict)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE

Lo stesso vale per il listvs[]


8
Ciò presuppone che BUILD_MAP e LOAD_GLOBAL siano un tempo costante e impieghino la stessa quantità di tempo. Altamente improbabile. timeit fornisce una stima molto migliore.
Jamie Pate

Più probabilmente, CALL_FUNCTIONrichiede almeno tanto tempo quanto BUILD_MAP(la funzione che viene chiamata essenzialmente lo è BUILD_MAP) e LOAD_GLOBALrichiede solo un sovraccarico aggiuntivo.
chepner


3

Nel caso della differenza tra [] e list (), c'è una trappola che non ho visto evidenziare da nessun altro. Se utilizzi un dizionario come membro dell'elenco, i due daranno risultati completamente diversi:

In [1]: foo_dict = {"1":"foo", "2":"bar"}

In [2]: [foo_dict]
Out [2]: [{'1': 'foo', '2': 'bar'}]

In [3]: list(foo_dict)
Out [3]: ['1', '2'] 

È possibile ottenere gli stessi risultati [foo_dict]utilizzando list((foo_dict,)). Il list()metodo accetta un iterabile in quanto è l'unico parametro e lo ripete per aggiungere elementi all'elenco. Ciò causerà una simile trappola facendo list(some_list)che appiattirà l'elenco.
sabato

1

list () e [] funzionano in modo diverso:

>>> def a(p=None):
...     print(id(p))
... 
>>> for r in range(3):
...     a([])
... 
139969725291904
139969725291904
139969725291904
>>> for r in range(3):
...     a(list())
... 
139969725367296
139969725367552
139969725367616

list () crea sempre un nuovo oggetto nell'heap, ma [] può riutilizzare la cella di memoria per molti motivi.


0

c'è una differenza nel comportamento tra [] e list () come mostra l'esempio seguente. dobbiamo usare list () se vogliamo che la lista dei numeri venga restituita, altrimenti otteniamo un oggetto mappa! Non sono sicuro di come spiegarlo però.

sth = [(1,2), (3,4),(5,6)]
sth2 = map(lambda x: x[1], sth) 
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>

sth2 = [map(lambda x: x[1], sth)]
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>
type(sth2) # list 
type(sth2[0]) # map

sth2 = list(map(lambda x: x[1], sth))
print(sth2) #[2, 4, 6]
type(sth2) # list
type(sth2[0]) # int

qui sembra esserci una spiegazione del comportamento usando l'esempio della funzione range () >>> print (range (10)) # range (0, 10) range () si comporta come una lista, ma non è una lista. È un oggetto che restituisce gli elementi successivi di una sequenza quando si itera su di esso, non fa realmente la lista, risparmiando spazio. tale oggetto è iterabile, cioè adatto come target per funzioni e costrutti che aspettano qualcosa da cui possono ottenere elementi successivi fino ad esaurimento della fornitura. La funzione list () crea elenchi da iterabili: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac

1
la conseguenza è che [] memorizza l'oggetto iterabile; list () crea un elenco dallo stesso iterabile
sebtac

0

Una coppia di parentesi quadre denota uno di un oggetto elenco o un pedice di indice, my_List [x].

Una coppia di parentesi graffe denota un oggetto dizionario.

a_list = ["on", "off", 1, 2]

a_dict = {on: 1, off: 2}


-5

È principalmente una questione di scelta il più delle volte. È una questione di preferenza.

Nota tuttavia che se ad esempio hai tasti numerici, non puoi farlo:

mydict = dict(1="foo", 2="bar")

Devi fare:

mydict = {"1":"foo", "2":"bar"}

7
Questo è sbagliato ... devi farlo mydict = {1:"foo", 2:"bar"}(senza virgolette per le chiavi).
6502

8
Non è semplicemente "sbagliato". Le chiavi sono stringhe / int a seconda che tu le citi o meno.
ThiefMaster
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.