[] und {} vs list () und dict (), was ist besser?

113

Ich verstehe, dass beide im Wesentlichen dasselbe sind, aber was den Stil betrifft, welcher ist der bessere (pythonischere), um eine leere Liste oder ein leeres Diktat zu erstellen?

Noah McIlraith
quelle

Antworten:

197

In Bezug auf die Geschwindigkeit ist es keine Konkurrenz für leere Listen / Diktate:

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

und für nicht leere:

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

Wenn Sie die Klammernotation verwenden, können Sie auch Listen- und Wörterbuchverständnisse verwenden, was Grund genug sein kann.

Greg Haskins
quelle
4
Das Diktat- und Listenverständnis kann auch unter Verwendung der englischen Namen erfolgen. Beispiel:list(i for i in range(10) if i % 2)
Zags
4
Gibt es einen Grund, warum {} und [] so viel schneller sind? Ich dachte, sie wären einfach Aliase.
Justin D.
Die Zeit scheint keine genaue Zeit anzugeben. Laut Benchmark scheint es ~ 200 ms zu dauern, was viel langsamer ist als bei normalen http-Aufrufen. Versuchen Sie, dict () normal in der Shell auszuführen und dann timeit ("dict ()") auszuführen. Sie würden sichtbare Unterschiede in der Ausführung feststellen.
Piyush
2
@piyush Tatsächlich gibt die timeit()Funktion die Gesamtzeit für die Ausführung einer bestimmten Anzahl von Iterationen an, was 1000000standardmäßig der Fall ist . Die obigen Beispiele geben also die Anzahl der Sekunden an, in denen das Code-Snippet millionenfach ausgeführt wird. Zum Beispiel timeit('dict()', number=1) // -> 4.0531158447265625e-06(eine Iteration) während timeit('dict()') // -> 0.12412905693054199(eine Million Iterationen)
Greg Haskins
@GregHaskins In diesem Fall sollte man sich keine Gedanken über die Verwendung von dict () oder {} machen, es sei denn, man durchläuft eine Million Datensätze und verwendet dict () in der Schleife.
Piyush
37

Meiner Meinung nach []und{} sind die pythonischsten und lesbarsten Möglichkeiten, leere Listen / Diktate zu erstellen.

Seien Sie jedoch vorsichtig set(), zum Beispiel:

this_set = {5}
some_other_set = {}

Kann verwirrend sein. Der erste erstellt eine Menge mit einem Element, der zweite erstellt ein leeres Diktat und keine Menge.

orlp
quelle
4
{}schafft immer ein leeres Diktat. {1,2,3}Erstellt einen Satz in 2.7+, ist jedoch in 2.6und in älteren Versionen ein Syntaxfehler .
ThiefMaster
1
Es tut uns leid? Das ist eine Variable mit einem Namen some_epic_set, die auf ein leeres dictObjekt zeigt. Es ist keine leere Menge. Für einen leeren Satz müssen Sie verwenden set().
6502
2
@ 6502: In der Tat, aber es ist eine häufige Gefahr, {5}die eine Menge mit einem Element erstellt 5und {}ein leeres Diktat ist.
Orlp
1
Wow, das war verwirrend. Trotzdem ist es nicht verwirrend. :-)
Prof. Falken
4
@EnderLook: Eigentlich mit dem Auspacken verallgemeinert , können Sie {*()}eine leere machen setmit Literalsyntax. Ich nenne es den einäugigen Affenoperator. :-)
ShadowRanger
17

Die dict wörtliche könnte ein seine winzig bisschen schneller als Bytecode kürzer:

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

Gleiches gilt für die listvs[]

DiebMaster
quelle
8
Dies setzt voraus, dass BUILD_MAP und LOAD_GLOBAL eine konstante Zeit sind und dieselbe Zeit benötigen. Sehr unwahrscheinlich. timeit gibt eine viel bessere Schätzung.
Jamie Pate
Wahrscheinlicher ist , CALL_FUNCTIONnimmt zumindest so viel Zeit wie BUILD_MAP(die Funktion im Wesentlichen ist genannt zu werden BUILD_MAP), und LOAD_GLOBALdauert nur zusätzlichen Aufwand ist.
Chepner
3

IMHO, mit list()und dict()lässt Ihr Python wie C. Ugh aussehen.

RichieHindle
quelle
3

Im Falle eines Unterschieds zwischen [] und list () gibt es eine Gefahr, auf die ich noch niemanden hingewiesen habe. Wenn Sie ein Wörterbuch als Mitglied der Liste verwenden, führen die beiden zu völlig unterschiedlichen Ergebnissen:

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
quelle
Sie können die gleichen Ergebnisse erzielen wie [foo_dict]mit list((foo_dict,)). Daslist() Methode verwendet eine iterable als einzigen Parameter und iteriert darüber, um der Liste Elemente hinzuzufügen. Dies führt zu einer ähnlichen Gefahr, list(some_list)wodurch die Liste abgeflacht wird.
Sotrh
1

list () und [] funktionieren unterschiedlich:

>>> 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 () erstellt immer ein neues Objekt im Heap, aber [] kann die Speicherzelle aus vielen Gründen wiederverwenden.

andreykyz
quelle
0

Es gibt einen Unterschied im Verhalten zwischen [] und list (), wie das folgende Beispiel zeigt. Wir müssen list () verwenden, wenn wir die Liste der Zahlen zurückgeben möchten, sonst erhalten wir ein Kartenobjekt! Ich bin mir nicht sicher, wie ich es erklären soll.

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
quelle
Hier scheint eine Erklärung des Verhaltens am Beispiel der Funktion range () zu sein. >>> print (range (10)) # range (0, 10) range () verhält sich wie eine Liste, ist jedoch keine Liste. Es ist ein Objekt, das die aufeinanderfolgenden Elemente aus einer Sequenz zurückgibt, wenn Sie darüber iterieren. Es erstellt die Liste nicht wirklich und spart Platz. Ein solches Objekt ist iterierbar, dh als Ziel für Funktionen und Konstrukte geeignet, die etwas erwarten, von dem sie aufeinanderfolgende Elemente erhalten können, bis der Vorrat erschöpft ist. Die Funktionsliste () erstellt Listen aus iterablen: >>> Liste (Bereich (5)) # [0, 1, 2, 3, 4]
sebtac
1
die Folge ist, dass [] das iterierbare Objekt speichert; list () erstellt eine Liste aus derselben iterierbaren
sebtac
0

Ein Kastenklammerpaar bezeichnet eines der Listenobjekte oder einen Indexindex, my_List [x].

Ein geschweiftes Klammerpaar bezeichnet ein Wörterbuchobjekt.

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

a_dict = {on: 1, off: 2}

Rohit Chaurasiya
quelle
-5

Es ist meistens eine Frage der Wahl. Es ist eine Frage der Präferenz.

Beachten Sie jedoch, dass Sie Folgendes nicht tun können, wenn Sie beispielsweise Zifferntasten haben:

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

Du musst:

mydict = {"1":"foo", "2":"bar"}
Ikke
quelle
7
Das ist falsch ... Sie müssen es tun mydict = {1:"foo", 2:"bar"}(ohne Anführungszeichen für Schlüssel).
6502
8
Es ist nicht einfach "falsch". Die Tasten sind Zeichenfolgen / Ints, je nachdem, ob Sie sie zitieren oder nicht.
ThiefMaster