ProgrammierungBackend-Entwickler

Beschreiben Sie den Mechanismus von Listenverständnissen (list comprehensions) in Python. Worin unterscheiden sich List Comprehension von der Funktion map() und von for-Schleifen, welche Vor- und Nachteile hat jeder Ansatz und welche Fehler können bei unsachgemäßer Anwendung auftreten?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Listenverständnisse (list comprehensions) sind eine prägnante Möglichkeit, Listen basierend auf vorhandenen iterierbaren Objekten mithilfe einer kurzen Syntax zu erstellen:

squares = [x**2 for x in range(10)]

Diese Notation ist äquivalent zu:

squares = [] for x in range(10): squares.append(x**2)

Listenverständnisse haben mehrere Vorteile:

  • Kürze und Lesbarkeit (insbesondere bei einfachen Transformationen);
  • Möglichkeit, Bedingungen einzugeben (filter): evens = [x for x in range(10) if x % 2 == 0];
  • Ausdrücke geben sofort eine Liste zurück, ihr Ergebnis kann weiterverwendet werden.

Analog zu map():

def f(x): return x**2 squares = list(map(f, range(10)))

map ist schneller bei großen Daten, wenn eine bereits in C vorhandene Funktion verwendet wird, und eignet sich für die Anwendung einer Funktion auf alle Elemente. List comprehension ist für beliebige Ausdrücke geeignet, nicht nur für vorhandene Funktionen. Die for-Schleife ist flexibler, aber umfangreicher.


Fangfrage.

Warum ist die Variable x nach der Ausführung der Liste in dem Ausdruck [x for x in range(10)] in Python2 außerhalb des Ausdrucks zugänglich, aber nicht in Python3?

Antwort: In Python2 behält die Schleifenvariable (x) ihren Wert nach der Ausführung des List Comprehensions. In Python3 wird sie "isoliert" und ist außerhalb der Liste nicht zugänglich, was unerwünschte Nebeneffekte verhindert.

Beispiel:

# Python 2.x: [x for x in range(3)] print(x) # x == 2 # Python 3.x: [x for x in range(3)] print(x) # NameError: name 'x' is not defined

Beispiele für reale Fehler aufgrund unzureichenden Wissens über die Feinheiten des Themas.


Geschichte 1

Ein Entwickler in einem großen Projekt wollte einen neuen Filter erstellen und eine neue Liste über list comprehension generieren:

my_list = [item.transform() for item in data if item.is_valid()]

Aber der Vorgang item.transform() verursachte einen Fehler, wenn item.is_valid() False zurückgab. Die Prüfungsfunktion war jedoch mit möglichen Nebeneffekten geschrieben, und letztendlich störte das Listenverständnis unerwartet Teile des Codes mit Nebenwirkungen.


Geschichte 2

Im Projekt gab es bei der Migration von Python2 auf Python3 einen Entwickler, der sich sicher war, dass die Schleifenvariable verfügbar bleibt:

[x for x in range(5)] print(x) # Erwartete 4, erhielt aber einen NameError.

Das führte zu einem Bug in der zyklischen Logik, wo die Variable außerhalb des Comprehensions benötigt wurde.


Geschichte 3

Die Verwendung von verschachtelten Listenverständnissen ohne explizite Angabe der Ebenen:

def flatten(matrix): return [cell for row in matrix for cell in row]

Anfänger machen häufig Fehler aufgrund einer falschen Reihenfolge in der Durchlauf (z.B. [cell for cell in row for row in matrix] oder überflüssige Verschachtelung), was zu einem falschen Ergebnis führt – ein eindimensionaler statt eines zweidimensionalen oder umgekehrt.