2016-08-06 16 views
1

Das folgende ist ein vereinfachtes Beispiel meines Codes.Verwendung von Vergleichen anstelle einer for-Schleife

>>> def action(num): 
     print "Number is", num 
>>> items = [1, 3, 6] 
>>> for i in [j for j in items if j > 4]: 
     action(i) 
Number is 6 

Meine Frage ist folgende: ist es schlechte Praxis (aus Gründen wie Code Klarheit) ersetzen Sie einfach die for Schleife mit einem Verständnis, das immer noch die action Funktion rufen? Das ist:

>>> (action(j) for j in items if j > 2) 
Number is 6 
+0

Nein ist es nicht, es ist tatsächlich schöner und schneller, denke ich, weil es zuerst keine Listen erstellt und Loops darüber, aber das eine Liste von None zurückgibt, weil Aktion nichts zurückgibt, und Sie würden '[]' für die Listenkomposition verwenden. –

+0

Das ist eigentlich eine Generatoraussage, die Sie dort bekommen haben, kein Listenverständnis. Ich weiß nicht, ob das Ihre Frage wesentlich beeinflusst. – Tagc

+0

@Tagc Ich weiß, es schafft einen Generator, war nicht sicher, ob Sie es ein Generator Verständnis nennen würde, aber ja die gleiche Idee für eine Liste Verständnis. Wäre einer aus irgendeinem Grund dem anderen vorzuziehen? – Siwel

Antwort

4

Dies sollte keinen Generator oder Verständnis überhaupt verwenden.

def action(num): 
    print "Number is", num 

items = [1, 3, 6] 
for j in items: 
    if j > 4: 
     action(i) 

Generatoren bewerten träge. Der Ausdruck (action(j) for j in items if j > 2) gibt lediglich einen Generatorausdruck an den Aufrufer zurück. Nichts wird darin geschehen, wenn Sie es nicht explizit erschöpfen. Listenkomprehensionen begutachten eifrig, aber in diesem speziellen Fall sind Sie mit einem list ohne Zweck verlassen. Verwenden Sie einfach eine normale Schleife.

+0

profitieren. "List Comprehensions evaluieren eifrig, aber in diesem speziellen Fall, Sie sind mit einer Liste ohne Zweck verlassen. Verwenden Sie einfach eine normale Schleife . " Während andere gute Punkte befürworteten, ist dies wirklich ein sehr starkes Argument * gegen * unter Verwendung von Generatorausdrücken/Listenkompromittierungen. Ich werde meine Antwort für diese Antwort einstufen. – Tagc

+0

Ist es besonders eine schlechte Idee, eine Liste "ohne Zweck" zu erstellen? – Siwel

+1

@ Siwel, natürlich. Wenn Sie nichts brauchen, erstellen Sie es nicht! Also - bessere Lesbarkeit und schnellere Codeausführung. –

1

Während ich persönlich Tigerhawk's solution bevorzuge, könnte es einen Mittelweg zwischen seiner und willywonkadailyblahs Lösung geben (jetzt gelöscht).

Ein willywonkadailyblah die Punkte waren:

Warum eine neue Liste erstellen, anstatt nur die alten verwenden? Sie haben bereits die Bedingung, die richtigen Elemente herauszufiltern, also warum sie in den Speicher legen und für sie zurückkommen?

Eine Möglichkeit, dieses Problem zu vermeiden, ist lazy evaluation der Filter dh zu verwenden haben die Filterung nur gemacht, wenn, indem das Filterteil eines Generators Ausdruck anstatt eine Liste Verständnis mit der for-Schleife iteriert:

for i in (j for j in items if j > 4): 
    action(i) 

Ausgabe

Number is 6 

In aller Ehrlichkeit, ich denke Tigerhaw Die Lösung von k ist dafür das Beste. Dies ist nur eine mögliche Alternative. Der Grund, warum ich dies vorgeschlagen habe, ist, dass es mich an viele LINQ-Abfragen in C# erinnert, wo Sie einen faulen Weg definieren, Elemente aus einer Sequenz in einer Anweisung zu extrahieren, zu filtern und zu projizieren (der LINQ-Ausdruck) und das dann tun kann Verwenden Sie eine separate for each-Schleife mit dieser Abfrage, um eine Aktion für jedes Element auszuführen.

1

Dies ist eine schlechte Praxis. Erstens erzeugt Ihr Codefragment nicht die gewünschte Ausgabe. Sie würden stattdessen etwas wie erhalten: <generator object <genexpr> at 0x03D826F0>.

Zweitens ist ein Listenverständnis zum Erstellen von Sequenzen und Generatoren ein zum Erstellen von Strömen von Objekten. Normalerweise haben sie keine Nebenwirkungen. Ihre Aktionsfunktion ist ein Paradebeispiel für einen Nebeneffekt - sie gibt ihre Eingabe aus und gibt nichts zurück. Vielmehr sollte ein Generator für jeden von ihm erzeugten Gegenstand eine Eingabe machen und eine Ausgabe berechnen. z.B.

doubled_odds = [x*2 for x in range(10) if x % 2 != 0] 

durch einen Generator verwenden Sie den Zweck Ihres Code sind Verschleiern, die globalen Zustand zu mutieren ist (Druck etwas), und nicht um einen Strom von Objekten zu erstellen. Während die Verwendung einer for-Schleife den Code etwas länger macht (im Prinzip nur mehr Leerzeichen), können Sie sofort erkennen, dass der Zweck darin besteht, Funktionen auf eine Auswahl von Elementen anzuwenden (im Gegensatz zu einem neuen Stream/einer Liste von Elementen). . Denken Sie daran,

for i in items: 
    if i < 4: 
     action(i) 

dass Generatoren noch Konstrukte werden Looping und dass die zugrunde liegende Bytecode ist mehr oder weniger das gleiche (wenn überhaupt etwas, Generatoren geringfügig weniger effizient sind), und Sie verlieren Klarheit. Generatoren und Listen-Comprehensions sind großartig, aber das ist nicht die richtige Situation für sie.