Code wie dieser passiert oft:
l = []
while foo:
#baz
l.append(bar)
#qux
Dies ist sehr langsam, wenn Sie Tausende von Elementen an Ihre Liste anhängen möchten, da die Größe der Liste ständig an die neuen Elemente angepasst werden muss.
In Java können Sie eine ArrayList mit einer anfänglichen Kapazität erstellen. Wenn Sie eine Vorstellung davon haben, wie groß Ihre Liste sein wird, ist dies viel effizienter.
Ich verstehe, dass Code wie dieser oft in ein Listenverständnis umgewandelt werden kann. Wenn die for / while-Schleife jedoch sehr kompliziert ist, ist dies nicht möglich. Gibt es ein Äquivalent für uns Python-Programmierer?
python
list
dictionary
initialization
Claudiu
quelle
quelle
Antworten:
Ergebnisse . (Bewerten Sie jede Funktion 144 Mal und mitteln Sie die Dauer)
Fazit . Es spielt kaum eine Rolle.
Vorzeitige Optimierung ist die Wurzel allen Übels.
quelle
Python-Listen haben keine integrierte Vorbelegung. Wenn Sie wirklich eine Liste erstellen müssen und den Aufwand für das Anhängen vermeiden müssen (und Sie sollten dies überprüfen), können Sie Folgendes tun:
Vielleicht könnten Sie die Liste vermeiden, indem Sie stattdessen einen Generator verwenden:
Auf diese Weise wird nicht jede Liste im Speicher gespeichert, sondern nur nach Bedarf generiert.
quelle
Kurzfassung: verwenden
eine Liste vorab zuzuweisen (dh in der Lage zu sein, 'Größen'-Elemente der Liste zu adressieren, anstatt die Liste schrittweise durch Anhängen zu bilden). Diese Operation ist sehr schnell, selbst auf großen Listen. Das Zuweisen neuer Objekte, die später Listenelementen zugewiesen werden, dauert VIEL länger und ist in Bezug auf die Leistung DER Engpass in Ihrem Programm.
Lange Version:
Ich denke, dass die Initialisierungszeit berücksichtigt werden sollte. Da in Python alles eine Referenz ist, spielt es keine Rolle, ob Sie jedes Element auf None oder eine Zeichenfolge setzen - so oder so ist es nur eine Referenz. Es dauert jedoch länger, wenn Sie für jedes zu referenzierende Element ein neues Objekt erstellen möchten.
Für Python 3.2:
Auswertung:
Wie Sie sehen können, dauert es nur sehr wenig, eine große Liste von Verweisen auf dasselbe None-Objekt zu erstellen.
Das Vorrücken oder Erweitern dauert länger (ich habe nichts gemittelt, aber nachdem ich dies einige Male ausgeführt habe, kann ich Ihnen sagen, dass das Erweitern und Anhängen ungefähr dieselbe Zeit dauert).
Zuweisen eines neuen Objekts für jedes Element - das dauert am meisten. Und die Antwort von S.Lott macht das - jedes Mal wird eine neue Zeichenfolge formatiert. Dies ist nicht unbedingt erforderlich. Wenn Sie Speicherplatz vorab zuweisen möchten, erstellen Sie einfach eine Liste mit "Keine" und weisen Sie den Listenelementen nach Belieben Daten zu. In beiden Fällen dauert das Generieren von Daten länger als das Anhängen / Erweitern einer Liste, unabhängig davon, ob Sie sie beim Erstellen der Liste oder danach generieren. Wenn Sie jedoch eine dünn besiedelte Liste wünschen, ist es definitiv schneller, mit einer Liste von None zu beginnen.
quelle
[]*
Ansatz verwendenDer pythonische Weg dafür ist:
oder welchen Standardwert Sie vorab bearbeiten möchten, z
[EDIT: Caveat Emptor Die
[Beer()] * 99
Syntax erstellt eineBeer
und füllt dann ein Array mit 99 Verweisen auf dieselbe einzelne Instanz.]Der Standardansatz von Python kann ziemlich effizient sein, obwohl diese Effizienz abnimmt, wenn Sie die Anzahl der Elemente erhöhen.
Vergleichen Sie
mit
Auf meinem Windows 7 i7 gibt es 64-Bit-Python
Während C ++ bietet (erstellt mit MSVC, 64-Bit, Optimierungen aktiviert)
C ++ - Debugbuild erzeugt:
Der Punkt hier ist, dass Sie mit Python eine Leistungsverbesserung von 7-8% erzielen können, und wenn Sie denken, dass Sie eine Hochleistungs-App schreiben (oder wenn Sie etwas schreiben, das in einem Webdienst oder etwas verwendet wird), dann Das ist nicht zu übersehen, aber Sie müssen möglicherweise Ihre Sprachwahl überdenken.
Außerdem ist der Python-Code hier nicht wirklich Python-Code. Wenn Sie hier zu wirklich pythoneskem Code wechseln, erhalten Sie eine bessere Leistung:
Welches gibt
(In 32-Bit ist doGenerator besser als doAllocate).
Hier ist die Lücke zwischen doAppend und doAllocate deutlich größer.
Offensichtlich gelten die Unterschiede hier wirklich nur, wenn Sie dies mehr als ein paar Mal tun oder wenn Sie dies auf einem stark belasteten System tun, auf dem diese Zahlen um Größenordnungen skaliert werden, oder wenn Sie es zu tun haben erheblich größere Listen.
Der Punkt hier: Machen Sie es auf pythonische Weise für die beste Leistung.
Wenn Sie sich jedoch Sorgen um die allgemeine Leistung auf hohem Niveau machen, ist Python die falsche Sprache. Das grundlegendste Problem besteht darin, dass Python-Funktionsaufrufe aufgrund von Python-Funktionen wie Dekoratoren usw. ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ) traditionell bis zu 300-mal langsamer waren als andere Sprachen .
quelle
timeit
timeit
, was Sie verwenden sollten, wenn Sie Ihren Python-Code zeitlich festlegen. Ich spreche natürlich nicht von C ++.bottles = [Beer()] * 99
erstellt keine 99 Bierobjekte. Erstellt stattdessen ein Beer-Objekt mit 99 Verweisen darauf. Wenn Sie es mutieren würden, würden alle Elemente in der Liste mutiert, Ursache(bottles[i] is bootles[j]) == True
für jedesi != j. 0<= i, j <= 99
.Wie andere bereits erwähnt haben, ist dies der einfachste Weg, eine Liste vorab zu erstellen
NoneType
Objekten erstellen.Davon abgesehen sollten Sie verstehen, wie Python-Listen tatsächlich funktionieren, bevor Sie entscheiden, dass dies notwendig ist. Bei der CPython-Implementierung einer Liste wird das zugrunde liegende Array immer mit Overhead-Raum in zunehmend größeren Größen erstellt
( 4, 8, 16, 25, 35, 46, 58, 72, 88, 106, 126, 148, 173, 201, 233, 269, 309, 354, 405, 462, 526, 598, 679, 771, 874, 990, 1120, etc)
, sodass die Größe der Liste nicht so häufig geändert wird.Aufgrund dieses Verhaltens sind die meisten
list.append()
FunktionenO(1)
für Anhänge komplex und weisen nur dann eine erhöhte Komplexität auf, wenn eine dieser Grenzen überschritten wird. An diesem Punkt wird die Komplexität seinO(n)
. Dieses Verhalten führt zu einer minimalen Verlängerung der Ausführungszeit in S. Lotts Antwort.Quelle: http://www.laurentluce.com/posts/python-list-implementation/
quelle
Ich habe den Code von @ s.lott ausgeführt und durch Vorabzuweisung die gleiche Leistungssteigerung von 10% erzielt. Ich habe @ jeremys Idee mit einem Generator ausprobiert und konnte die Leistung des Gens besser sehen als die des doAllocate. Für mein Projekt sind die 10% Verbesserung wichtig, also danke an alle, da dies einem Haufen hilft.
quelle
Bedenken hinsichtlich der Vorbelegung in Python treten auf, wenn Sie mit numpy arbeiten, das mehr C-ähnliche Arrays enthält. In diesem Fall betreffen Bedenken hinsichtlich der Vorzuweisung die Form der Daten und den Standardwert.
Betrachten Sie Numpy, wenn Sie numerische Berechnungen für umfangreiche Listen durchführen und Leistung wünschen.
quelle
Für einige Anwendungen ist ein Wörterbuch möglicherweise das, wonach Sie suchen. In der Methode find_totient fand ich es beispielsweise bequemer, ein Wörterbuch zu verwenden, da ich keinen Nullindex hatte.
Dieses Problem könnte auch mit einer vorab zugewiesenen Liste gelöst werden:
Ich bin der Meinung, dass dies nicht so elegant und fehleranfällig ist, weil ich None speichere, was eine Ausnahme auslösen könnte, wenn ich sie versehentlich falsch verwende, und weil ich über Randfälle nachdenken muss, die ich auf der Karte vermeiden kann.
Es ist wahr, dass das Wörterbuch nicht so effizient ist, aber wie andere kommentiert haben, sind kleine Geschwindigkeitsunterschiede nicht immer erhebliche Wartungsrisiken wert .
quelle
Soweit ich weiß, sind Python-Listen ArrayLists bereits ziemlich ähnlich. Aber wenn Sie diese Parameter optimieren möchten, fand ich diesen Beitrag im Internet, der interessant sein könnte (im Grunde erstellen Sie einfach Ihre eigene
ScalableList
Erweiterung):http://mail.python.org/pipermail/python-list/2000-May/035082.html
quelle