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

113

Rozumiem, że oba są zasadniczo tym samym, ale jeśli chodzi o styl, który z nich jest lepszy (bardziej Pythonic) do utworzenia pustej listy lub dyktu?

Noah McIlraith
źródło

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.

Greg Haskins
źródło
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.

orlp
źródło
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[]

ThiefMaster
źródło
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

IMHO, używanie list()i dict()sprawia, że ​​twój Python wygląda jak C. Ugh.

RichieHindle
źródło
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'] 
oxtay
źródło
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.

andreykyz
źródło
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
sebtac
źródło
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}

Rohit Chaurasiya
źródło
-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"}
Ikke
źródło
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