[] i {} vs list () i dict (), co jest lepsze?


Odpowiedzi:


197

Pod względem szybkości nie ma konkurencji dla pustych list / dykt:

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

a dla niepustych:

>>> 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

Ponadto, użycie notacji z nawiasami kwadratowymi pozwala na użycie list i słowników, co może być wystarczającym powodem.


4
Zrozumienie dyktowania i listy można również wykonać przy użyciu nazw angielskich. Przykład:list(i for i in range(10) if i % 2)
Zags

4
czy istnieje powód, dla którego {} i [] są tak dużo szybsze? Myślałem, że to po prostu aliasy.
Justin D.

Wydaje się, że czas nie daje dokładnego czasu. Zgodnie z benchmarkiem wydaje się, że zajmuje to ~ 200 ms, co jest znacznie wolniejsze niż zwykłe wywołania http. Spróbuj uruchomić dict () normalnie w powłoce, a następnie uruchom timeit ("dict ()"), zobaczysz widoczną różnicę w wykonaniu.
pijusz

2
@piyush W rzeczywistości timeit()funkcja raportuje całkowity czas wykonania określonej liczby iteracji, co jest 1000000wartością domyślną. Zatem powyższe przykłady to liczba sekund potrzebna do uruchomienia fragmentu kodu milion razy. Na przykład timeit('dict()', number=1) // -> 4.0531158447265625e-06(jedna iteracja) podczas timeit('dict()') // -> 0.12412905693054199(milion iteracji)
Greg Haskins

@GregHaskins, więc w takim przypadku nie wydaje mi się, żeby ktoś miał się martwić o używanie dict () lub {}, chyba że przejdzie przez milion rekordów i użyje dict () w pętli.
piyusz

37

Moim zdaniem []i {}są najbardziej pytonicznymi i czytelnymi sposobami tworzenia pustych list / dykt.

Uważaj set()jednak, na przykład:

this_set = {5}
some_other_set = {}

Może być mylące. Pierwsza tworzy zestaw z jednym elementem, druga tworzy pusty dykt, a nie zestaw.


4
{}zawsze tworzy pusty dykt. {1,2,3}tworzy zestaw w wersji 2.7+, ale jest błędem składniowym w 2.6i starszych wersjach.
ThiefMaster

1
Przepraszam? to jest zmienna o nazwie some_epic_setwskazującej na pusty dictobiekt ... to nie jest pusty zbiór. Aby uzyskać pusty zestaw, musisz użyć set().
6502

2
@ 6502: Rzeczywiście, ale jest to powszechna pułapka, która {5}tworzy zestaw z jednym elementem 5i {}jest pustym nakazem.
orlp

1
Wow, to było zagmatwane. Jednak nie jest to mylący poziom Fraktal złego projektu. :-)
Prof. Falken

4
@EnderLook: Właściwie, przy rozpakowywaniu uogólnionym , możesz użyć {*()}do zrobienia pustego setz literałem składni. Nazywam to jednooką małpą operatorem. :-)
ShadowRanger

17

Dict dosłowna może być drobny trochę szybciej, jej kod bajtowy jest krótszy:

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

To samo dotyczy listvs[]


8
Zakłada się, że BUILD_MAP i LOAD_GLOBAL są stałe i zajmują taką samą ilość czasu. Wysoce nieprawdopodobne. to daje znacznie lepsze oszacowanie.
Jamie Pate

Bardziej prawdopodobne jest, że CALL_FUNCTIONzajmuje co najmniej tyle samo czasu, ile BUILD_MAP(wywoływana funkcja zasadniczo jest BUILD_MAP), a LOAD_GLOBALtrwa to tylko dodatkowe obciążenie.
chepner


3

W przypadku różnicy między [] i list () istnieje pułapka, na którą nie widziałem nikogo innego. Jeśli użyjesz słownika jako członka listy, oba dadzą zupełnie inne wyniki:

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'] 

Możesz uzyskać takie same wyniki, jak [foo_dict]przy użyciu list((foo_dict,)). list()Metoda bierze iterable jak to tylko parametr i iteracje nad nim, aby dodać elementy do listy. Spowoduje to podobną pułapkę, jeśli list(some_list)spowoduje to spłaszczenie listy.
sotrh

1

list () i [] działają inaczej:

>>> 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 () zawsze tworzy nowy obiekt w stercie, ale [] może ponownie użyć komórki pamięci z wielu powodów.


0

istnieje jedna różnica w zachowaniu między [] i list (), jak pokazuje poniższy przykład. musimy użyć list (), jeśli chcemy zwrócić listę liczb, w przeciwnym razie otrzymamy obiekt mapy! Nie wiem jednak, jak to wyjaśnić.

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

tutaj wydaje się być wyjaśnieniem zachowania na przykładzie funkcji range () >>> print (range (10)) # range (0, 10) range () zachowuje się jak lista, ale nie jest listą. Jest to obiekt, który zwraca kolejne elementy sekwencji podczas iteracji po niej, tak naprawdę nie tworzy listy, oszczędzając miejsce. taki obiekt jest iterowalny, to znaczy odpowiedni jako cel dla funkcji i konstrukcji, które oczekują czegoś, z czego mogą uzyskać kolejne elementy, aż do wyczerpania zasobów. Funkcja list () tworzy listy z iterable: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac

1
w konsekwencji [] przechowuje iterowalny obiekt; list () tworzy listę z tego samego
iterowalnego

0

Para nawiasów prostokątnych oznacza jeden z obiektów listy lub indeks indeksu, my_List [x].

Para nawiasów klamrowych oznacza obiekt słownika.

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

a_dict = {on: 1, off: 2}


-5

W większości przypadków jest to kwestia wyboru. To kwestia preferencji.

Pamiętaj jednak, że jeśli masz na przykład klawisze numeryczne, nie możesz tego zrobić:

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

Musisz zrobić:

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

7
To jest złe ... musisz to zrobić mydict = {1:"foo", 2:"bar"}(bez cudzysłowów dla kluczy).
6502

8
To nie jest po prostu „złe”. Klucze są łańcuchami / intami w zależności od tego, czy je zacytujesz, czy nie.
ThiefMaster
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.