2016-06-13 6 views
6

So habe ich diese Beispiele aus der offiziellen Dokumentation. https://docs.python.org/2/library/timeit.htmlListe vs Generator Verständnis Geschwindigkeit mit Join-Funktion

Was genau macht das erste Beispiel (Generator Ausdruck) langsamer als das zweite (Listenverständnis)?

>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000) 
0.8187260627746582 
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000) 
0.7288308143615723 
+0

Siehe Ray Hettinger die Antwort hier http://StackOverflow.com/Questions/9060653/list-comprehension-without-python –

+0

@BhargavRao - Während ich stimme, dass Raymonds Antwort diese Frage anspricht, ist diese Frage grundlegend anders als _that_ Frage. (Hier will OP wissen, warum List-Comp schneller ist - in der anderen Frage kannte OP nicht einmal den Unterschied zwischen einem Generator oder einem List-Comp ...). Ich denke, ich bin mir nicht sicher, was die Politik sein sollte, um den Dump-Hammer in Fällen wie diesen zu bringen ... – mgilson

+1

@mgilson Die andere Frage ist ein super Satz dieser Frage. Es gab einen Beitrag zu Meta, der besagt, dass wir als Duplikat einer breiteren Frage abstimmen können. Wie zum Beispiel, schließen * Wie konvertiere ich das zu einem Listenverständnis * als ein Duplikat von * Was ist ein Listen-Comp, wie funktioniert es *. Es gibt Versuche, breitere Fragen zu erstellen, um Ops zu helfen (siehe [cannon] (http://sopython.com/canon/)). Alles in allem, wenn eine bestimmte Frage woanders beantwortet wurde, schließen wir als dumme. (Ich bin gegen die Beschreibung, die sagt * genaue Dupe * für Hämmer anstelle der normalen hat eine Antwort) –

Antwort

9

Die str.join Methode wandelt seine iterable Parameter auf eine Liste, wenn es bereits keine Liste oder Tupel ist. Dadurch kann die Verknüpfungslogik mehrere Male über die Elemente iterieren (es wird ein Durchgang ausgeführt, um die Größe der Ergebniszeichenfolge zu berechnen, und dann ein zweiter Durchlauf, um die Daten tatsächlich zu kopieren).

Sie können dies in the CPython source code sehen:

PyObject * 
PyUnicode_Join(PyObject *separator, PyObject *seq) 
{ 
    /* lots of variable declarations at the start of the function omitted */ 

    fseq = PySequence_Fast(seq, "can only join an iterable"); 

    /* ... */ 
} 

Die PySequence_Fast Funktion in der C-API tut genau das, was ich beschrieben. Er konvertiert ein beliebiges iterables in eine Liste (im Wesentlichen durch Aufruf von list), es sei denn, es ist bereits eine Liste oder ein Tupel.

Die Umwandlung des Generatorausdrucks in eine Liste bedeutet, dass die üblichen Vorteile von Generatoren (ein kleinerer Speicherbedarf und das Potenzial zum Kurzschließen) nicht für str.join gelten, und so der (kleine) zusätzliche Overhead Generator hat seine Leistung verschlechtert.