Python-For-In-Schleife, der eine Variable vorangestellt ist

77
foo = [x for x in bar if x.occupants > 1]

Nachdem ich hier gegoogelt und gesucht hatte, konnte ich nicht herausfinden, was dies bewirkt. Vielleicht habe ich nicht das richtige Zeug gesucht, aber hier ist es. Jede Eingabe zum Entlarven dieser Kurzschrift wird sehr geschätzt.

Greg Flynn
quelle
6
@ Greg, ich habe gegoogelt python "* for * in * if"und dies war der erste Treffer secnetix.de/olli/Python/list_comprehensions.hawk
John La Rooy

Antworten:

84

Die aktuellen Antworten sind gut, aber sprechen Sie nicht darüber, wie sie nur syntaktischer Zucker für ein Muster sind, an das wir so gewöhnt sind.

Beginnen wir mit einem Beispiel, sagen wir, wir haben 10 Zahlen, und wir wollen eine Teilmenge von denen, die größer als beispielsweise 5 sind.

>>> numbers = [12, 34, 1, 4, 4, 67, 37, 9, 0, 81]

Für die obige Aufgabe sind die folgenden Ansätze völlig identisch und gehen von ausführlich bis prägnant, lesbar und pythonisch :

Ansatz 1

result = []
for index in range(len(numbers)):
    if numbers[index] > 5:
        result.append(numbers[index])
print result  #Prints [12, 34, 67, 37, 9, 81]

Ansatz 2 (etwas sauberere For-In-Schleifen)

result = []
for number in numbers:
    if number > 5:
        result.append(number)
print result  #Prints [12, 34, 67, 37, 9, 81]

Ansatz 3 (Listenverständnis eingeben)

result = [number for number in numbers if number > 5]

oder allgemeiner:

[function(number) for number in numbers if condition(number)]

wo:

  • function(x)ein nimmt xund verwandelt es in etwas Nützliches (wie zum Beispiel: x*x)
  • Wenn condition(x)ein False-y-Wert zurückgegeben wird (False, None, leere Zeichenfolge, leere Liste usw.), wird die aktuelle Iteration übersprungen (think continue). Wenn die Funktion einen Nicht-False-y-Wert zurückgibt, gelangt der aktuelle Wert zum endgültigen resultierenden Array (und durchläuft den obigen Transformationsschritt).

Um die Syntax etwas anders zu verstehen, lesen Sie den Abschnitt Bonus unten.

Weitere Informationen finden Sie im Tutorial, das alle anderen Antworten verlinkt haben: Listenverständnis


Bonus

(Etwas unpythonisch, aber der Vollständigkeit halber hier)

Das obige Beispiel kann wie folgt geschrieben werden:

result = filter(lambda x: x > 5, numbers)

Der obige allgemeine Ausdruck kann wie folgt geschrieben werden:

result = map(function, filter(condition, numbers)) #result is a list in Py2
UltraInstinct
quelle
Ich würde das erste allgemein als Ausdruck bezeichnen ; Wenn es nur so ist x*x, ist es oft nur da und nicht square(x). Es macht es noch schmerzhafter dann , wenn ich diesen Ausdruck sehe in ein Lambda - Dosen, zB [x**2 for x in range(5)]gegenüber map(lambda x: x**2, range(5)).
Nick T
26

Es ist ein Listenverständnis

foowird eine gefilterte Liste barder Objekte mit dem Attribut Insassen> 1 sein

barkann ein list, set, dictoder jede andere iterable

Hier ist ein Beispiel zur Verdeutlichung

>>> class Bar(object):
...   def __init__(self, occupants):
...     self.occupants = occupants
... 
>>> bar=[Bar(0), Bar(1), Bar(2), Bar(3)]
>>> foo = [x for x in bar if x.occupants > 1]
>>> foo
[<__main__.Bar object at 0xb748516c>, <__main__.Bar object at 0xb748518c>]

Foo hat also 2 BarObjekte, aber wie überprüfen wir, welche es sind? Fügen wir eine __repr__Methode hinzu, Bardamit sie informativer ist

>>> Bar.__repr__=lambda self:"Bar(occupants={0})".format(self.occupants)
>>> foo
[Bar(occupants=2), Bar(occupants=3)]
John La Rooy
quelle
2
Diese Antwort ist strikt besser als die akzeptierte Antwort, jedoch nicht als solche gekennzeichnet, da sie 4 Minuten später einging.
user1717828
1

Soweit ich das beurteilen kann, sollte dies so funktionieren, dass überprüft wird, ob die Liste "bar" leer ist (0) oder aus einem Singleton (1) über x.occupants besteht, wobei x ein definiertes Element in der Listenleiste ist und kann die Eigenschaft von Insassen haben. Also wird foo aufgerufen, geht die Liste durch und gibt dann alle Elemente zurück, die die Prüfbedingung x.occupant bestehen.

In einer Sprache wie Java würden Sie eine Klasse namens "x" erstellen, in der 'x'-Objekte dann einem Array oder ähnlichem zugewiesen werden. X hätte ein Feld namens "Insassen" und jeder Index würde mit der Methode x.occupants überprüft, die die Nummer zurückgibt, die dem Insassen zugewiesen ist. Wenn diese Methode größer als 1 zurückgibt (wir nehmen an, dass ein int hier als Teilbelegung ungerade wäre), würde die foo-Methode (die auf dem fraglichen Array oder ähnlich aufgerufen wird) ein Array oder ähnliches zurückgeben, wie in der foo-Methode definiert für dieses Container-Array oder was haben Sie. Die Elemente des zurückgegebenen Arrays wären die 'x'-Objekte im ersten Array-Ding, die den Kriterien von "Größer als 1" entsprechen.

Python verfügt über integrierte Methoden über das Listenverständnis, um dies viel prägnanter und erheblich vereinfacht zu handhaben. Anstatt zwei vollständige Klassen und mehrere Methoden zu implementieren, schreibe ich diese eine Codezeile.

Weltingenieur
quelle
Siehe das Beispiel, das ich meiner Antwort hinzugefügt habe
John La Rooy
0

Dies gibt eine Liste zurück, die alle Elemente in der Leiste enthält, deren Insassen> 1 sind.

Kien Truong
quelle
0

Da der Programmierteil der Frage von anderen vollständig beantwortet wird, ist es schön, seine Beziehung zur Mathematik zu kennen ( Mengenlehre ). Eigentlich ist es die Python-Implementierung der Set Builder-Notation :

Definieren einer Menge durch ein Axiom der Spezifikation :

B = {x є A: S (x)}

Englische Übersetzung: B ist eine Menge, in der seine Mitglieder aus A ausgewählt werden , also ist B eine Teilmenge von A (B ⊂ A), wobei die durch die Funktion S angegebenen Merkmale gelten :S(x) == True

Definieren von B mithilfe des Listenverständnisses:

B = [x für x in A, wenn S (x)]

Um B mit Listenverständnis zu erstellen , werden die Mitglieder von B (bezeichnet mit x ) aus Satz A ausgewählt, wobei S(x) == True(Einschlussbedingung).

Hinweis: Eine Funktion, Sdie einen Booleschen Wert zurückgibt, wird als Prädikat bezeichnet .

Xaqron
quelle