Listen — viele Werte unter einem Namen
Beliebig viele Werte unter einem Namen halten, mit Index und Slice hineingreifen, die Methoden, die eine Liste verändern, und die Falle, dass zwei Namen an derselben Liste hängen.
Wie möchtest du lernen?
Das Problem, das wir lösen
Ein Laden muss die Preise von drei Produkten speichern. Mit allem, was wir bisher gelernt haben, gibt es nur einen Weg:
price_1 = 15
price_2 = 60
price_3 = 850
print(price_1 + price_2 + price_3)925Und jetzt die Frage: Was ist mit vierzig Produkten? Vierzig Variablen. Und eine Rechnung mit vierzig Teilen. Und wenn der Laden etwas Neues verkauft, musst du in den Code gehen und eine weitere Variable erfinden.
Das Problem ist nicht nur das Tippen, es ist die Struktur. Für Python sind price_1, price_2 und price_3 drei völlig unabhängige Namen — so unabhängig wie name und age. Du weißt, dass es drei Instanzen desselben Dings sind. Wir haben schlicht noch keine Möglichkeit im Code, „viele vom gleichen Ding“ zu schreiben.
Eine Liste ist dieser Weg. Ein Name, beliebig viele Werte darunter, in Reihenfolge.
Am Ende dieses Kapitels kannst du
- Eine Liste bauen und mit einem Index und einem Slice hineingreifen
- Eine Liste mit
append,insert,removeundpopverändern - Erklären, warum eine Liste verändert werden kann, ein Stück Text aber nicht
- Erkennen und vermeiden, dass
b = azwei Namen an eine Liste bindet - Einen
IndexErrorund einenValueErrorlesen und sagen, was schiefging
Voraussetzungen: for-Schleifen und range.
Eine Liste erstellen
Eckige Klammern, Werte durch Kommas getrennt:
prices = [15, 60, 850]
print(prices)
print(len(prices))[15, 60, 850]
3len() funktioniert hier genau wie bei Text — drei Werte, also 3.
Beim Ausgeben siehst du die ganze Liste, Klammern inklusive. Das ist nicht für einen Benutzer zum Lesen, sondern damit du verstehst: [15, 60, 850] sagt dir, dass es eine Liste ist, nicht 925.
Hineingreifen
Indexieren funktioniert genau wie bei Strings — Zählen ab null, negative von hinten:
prices = [15, 60, 850]
print(prices[0])
print(prices[-1])
print(prices[1:])15
850
[60, 850]Alle drei Zeilen folgen den Regeln aus Kapitel sechs, unverändert. Ein Unterschied fällt auf: prices[0] gibt eine Zahl zurück, während prices[1:] eine Liste gibt. Ein Slice liefert immer die gleiche Art zurück, aus der er geschnitten wurde, nie ein einzelnes Stück.
Und hier ist der echte Unterschied: eine Liste kann verändert werden
In Kapitel sechs haben wir gesehen, dass ein Zeichen im Text nicht ausgetauscht werden kann:
name = "rafi"
name[0] = "R"TypeError: 'str' object does not support item assignmentDie identische Zeile funktioniert bei einer Liste:
prices = [15, 60, 850]
prices[0] = 20
print(prices)[20, 60, 850]Keine neue Liste wurde gebaut — diese Liste hat sich verändert. Das ist die wichtigste Eigenschaft einer Liste, und die Falle am Ende dieses Kapitels kommt genau daraus.
Die Begriffe dafür: Text ist unveränderlich (immutable), eine Liste ist veränderlich (mutable).
Hinzufügen und Wegnehmen
stock = ["pen", "notebook"]
stock.append("bag")
stock.insert(1, "eraser")
print(stock)
stock.remove("pen")
print(stock)
last = stock.pop()
print(last)
print(stock)['pen', 'eraser', 'notebook', 'bag']
['eraser', 'notebook', 'bag']
bag
['eraser', 'notebook']Vier Methoden, vier verschiedene Jobs:
append(x)— fügt am Ende aninsert(i, x)— setzt es an Positioni, alles danach rückt nach rechtsremove(x)— findet den ersten Eintrag mit diesem Wert und wirft ihn rauspop()— wirft das letzte Element raus und gibt es zurück
Der Unterschied zwischen den letzten beiden ist die Hauptverwirrungsquelle: remove will wissen, was raus soll, pop will wissen, woher. Und pop gibt dir das Entfernte zurück; remove nicht.
Diese Methoden geben die Liste nicht zurück. Bei Text musstest du das Ergebnis vonname.upper()aufbewahren, weil es neuen Text baute und zurückgab. Listen sind andersherum:appendverändert die Liste selbst und gibtNonezurück.
Daraus entsteht der klassische Fehler:
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)NoneDie Liste ist weg. Schreib stock.append("bag"), nicht stock = stock.append("bag").
Suchen und Durchlaufen
stock = ["pen", "notebook", "bag"]
print("pen" in stock)
print("chair" in stock)
for item in stock:
print(item.upper())True
False
PEN
NOTEBOOK
BAGin suchte in Text, und es durchsucht eine Liste auch — dasselbe Wort, derselbe Job.
Und for item in stock läuft die Werte einzeln ab. Beachte: kein range, keine Index-Arithmetik, genau wie beim Durchlaufen der Zeichen eines Worts in Kapitel elf.
Wenn du Position und Wert brauchst, enumerate:
stock = ["pen", "notebook"]
for position, item in enumerate(stock, start=1):
print(position, item)1 pen
2 notebookOhne start=1 beginnt die Zählung bei null. Eine Liste, die einem Menschen gezeigt wird, will meist bei eins anfangen.
Die Falle, die jeden erwischt
In Kapitel vier haben wir das hier gesehen:
a = 3
b = a
b = b + 1
print(a, b)3 4b bekam einen Wert und beobachtete a nicht. Mach dasselbe mit einer Liste:
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)[1, 2, 3, 4]
[1, 2, 3, 4]b wurde geändert, und a hat sich auch geändert.
Der Grund widerspricht der früheren Regel nicht, er ist die frühere Regel. In der Zeile b = a bekam b genau das, was a hielt — und was a hielt war wo die Liste ist, keine Kopie der Liste. Also zeigen jetzt beide Namen auf dieselbe Liste. b.append(4) veränderte diese eine Liste, und beide Namen zeigen dieselbe Veränderung.
Du siehst das nie bei Zahlen, weil b = b + 1 die alte Zahl nicht modifiziert — es baut eine neue und legt sie in b. Zahlen sind sicher, genau weil sie nicht verändert werden können. Listen können, also sind sie es nicht.
Wenn du eine eigene Kopie willst, musst du sie anfordern:
a = [1, 2, 3]
b = a.copy()
b.append(4)
print(a)
print(b)[1, 2, 3]
[1, 2, 3, 4]Wann du aufpassen musst. Immer dann, wenn du eine Liste unter einen zweiten Namen legst, oder eine Liste in eine Funktion übergibst (Kapitel neunzehn), frag dich einmal: will ich diese eine verändern, oder will ich eine Kopie? Die Leute, die diese Frage nie stellen, verbringen Tage damit, Bugs zu jagen, die sich lesen wie „aber ich habe hier doch nichts geändert“.
Ein vollständiges Beispiel
shopping.py:
# A shopping list, built up and then summarised
items = []
items.append("pen")
items.append("notebook")
items.append("bag")
items.insert(0, "eraser")
print("List :", items)
print("Count :", len(items))
print("First :", items[0])
print("Last :", items[-1])
print("Has bag :", "bag" in items)
items.remove("pen")
dropped = items.pop()
print()
print("After removing 'pen' and popping the last one:")
print("List :", items)
print("Dropped :", dropped)
print("Count :", len(items))
print()
print("Numbered:")
for position, item in enumerate(items, start=1):
print(f" {position}. {item}")List : ['eraser', 'pen', 'notebook', 'bag']
Count : 4
First : eraser
Last : bag
Has bag : True
After removing 'pen' and popping the last one:
List : ['eraser', 'notebook']
Dropped : bag
Count : 2
Numbered:
1. eraser
2. notebookDrei Dinge, die man bemerken sollte.
Es beginnt mit einer leeren Liste. Die Zeile items = [] macht denselben Job wie ein Akkumulator außerhalb einer Schleife in Kapitel zehn — wo total = 0 war, ist jetzt []. Du brauchst einen Ort zum Sammeln, bevor du anfängst zu sammeln.
insert(0, "eraser") setzt es an den Anfang, also ist eraser zuerst in der ausgegebenen Liste. Die Reihenfolge, in der Dinge hinzugefügt wurden, ist nicht die Reihenfolge, in der sie am Ende stehen.
pop() gab das Entfernte zurück, also hält dropped das bag. remove("pen") gab nichts zurück, also ist das entfernte pen einfach weg.
Wenn etwas schiefgeht
IndexError: list index out of range Ein Index jenseits der Anzahl der Werte in der Liste. In einer Liste von dreien sind die gültigen Indexe 0, 1, 2 — es gibt kein prices[3]. Für den letzten Wert ist prices[-1] das Sicherste, weil es keine Kenntnis der Länge braucht.
ValueError: list.remove(x): x not in list Der Wert, den du entfernen wolltest, ist nicht da. Prüfe vorher mit if x in stock:, oder nutze try aus Kapitel vierundzwanzig.
AttributeError: 'NoneType' object has no attribute 'append' Eine frühere Zeile sagte stock = stock.append(...), also ist stock jetzt None. Behalte das Ergebnis nicht — stock.append(...) für sich allein ist die ganze Operation.
Ich habe eine Liste geändert und eine andere hat sich auch geändert Zwei Namen hängen an einer Liste. Schreib b = a.copy() statt b = a.
Ich entferne in einer Schleife und Dinge werden übersprungen
numbers = [1, 2, 2, 3, 4]
for n in numbers:
if n % 2 == 0:
numbers.remove(n)
print(numbers)[1, 2, 3]Eine 2 hat überlebt. Das Verkürzen der Liste, die du abläufst, bringt Pythons Zählung mit den Positionen der Liste aus dem Tritt, also werden einige Werte übersprungen. Die Lösung ist nicht zu entfernen, sondern das, was du behalten willst, in eine neue Liste zu sammeln.
numbers = [1, 2, 2, 3, 4]
kept = []
for n in numbers:
if n % 2 != 0:
kept.append(n)
print(kept)[1, 3]Ich habe eine Variable list genannt und jetzt funktioniert list(...) nicht mehr list ist einer von Pythons eigenen Namen. Nimm einen aussagekräftigen — items, prices, names.
Schritt 4 von 6 — Vorhersagen
Prüfe dein Verständnis
Das Ergebnis von append wird wieder in stock gespeichert. Was wird ausgegeben?
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)- ANone
- B['pen', 'notebook', 'bag']
- C['bag']
- DEin `AttributeError`
Nur b wurde geändert. Was geben die beiden Zeilen aus?
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)- A[1, 2, 3] [4]
- B[1, 2, 3] [1, 2, 3, 4]
- C[1, 2, 3, 4] [1, 2, 3]
- D[1, 2, 3, 4] [1, 2, 3, 4]
Die Liste hält drei Werte und Index drei wird abgefragt. Was passiert?
prices = [15, 60, 850]
print(prices[3])- AEine leere Liste
- BEin `IndexError` — bei drei Werten sind die gültigen Indexe `0`, `1`, `2`
- CNone
- D850 — der letzte Wert
Zum Antworten brauchst du ein Konto
Melde dich an, um deine Antworten zu prüfen
Die Fragen stehen oben, und sie im Kopf durchzuarbeiten ist der wichtige Teil. Melde dich an, um die Antworten, die Erklärungen und die dreistufigen Hinweise zu sehen.
Jetzt bist du dran
Schreib eine Datei namens marks.py, die eine Liste von mindestens sechs Noten hält.
Dann gib aus:
- Die ganze Liste, und wie viele Noten darin sind
- Die erste und die letzte Note — nutze
[-1]für die letzte - Die Summe und den Durchschnitt, akkumuliert mit einer Schleife statt von Hand einzutippen
- Eine nummerierte Liste mit
enumerate, beginnend bei eins - Eine neue Liste der bestandenen Noten (40 oder mehr), und wie viele es sind
Dann führ zwei Experimente durch, und beide zählen:
- Häng eine weitere Note mit
appendans Ende an und gib die Summe wieder aus. Musstest du die Zeile ändern, die sie berechnet? Wenn nicht, hast du eine echte Berechnung geschrieben. - Schreib
backup = marks, dannmarks.append(100), und gib beide aus. Was ist inbackup? Mach jetzt dasselbe mit.copy()und schau dir den Unterschied an.
Das letzte Experiment sind die wertvollsten drei Minuten in diesem Kapitel. Es einmal mit eigenen Augen zu sehen heißt, später keinen Nachmittag mehr damit zu verbringen.
Schritt 6 von 6
Herausforderung — das Kapitel-Quiz
Zehn Fragen von leicht bis schwer. Die letzten sind absichtlich knifflig.
Melde dich an, um das Quiz zu machen