Aufwärmen · Aufgabe 1 von 7
Aufwärmen aus Lektion I3.3: Was gibt dieser Code aus?
g = (n * 2 for n in [1, 2, 3])
print(next(g), sum(g))// I3.4 · ca. 35 Min. · Aufbau
Nach dieser Lektion verbinden, schneiden und stückeln Sie jedes Iterable mit chain, islice und batched, gruppieren sortierte Daten mit groupby und bilden laufende Summen und Kombinationen mit accumulate und product.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
g = (n * 2 for n in [1, 2, 3])
print(next(g), sum(g))Vorhersagen · Aufgabe 2 von 7
from itertools import groupby
for key, group in groupby("AABAA"):
print(key, len(list(group)), end="; ")Üben · Aufgabe 3 von 7
from itertools import islice
def naturals():
n = 1
while True:
yield n
n += 1
print(list(____(naturals(), 3)))Üben · Aufgabe 4 von 7
from itertools import chain
print(list(chain([1, 2], "ab", range(2))))Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
from itertools import groupby
groups = {}
for key, group in groupby("aabbb"):
groups[key] = group
print({k: list(g) for k, g in groups.items()})Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Die Bestellungen zweier Schichten werden mit chain verbunden, und islice wirft einen Blick auf die ersten beiden. sorted und groupby zeigen, wer welches Getränk bestellt hat, mit einer Schlüsselfunktion für beide. accumulate liefert die laufende Zahl der Tassen, batched setzt je zwei Gäste an einen Tisch, und product baut die Karte aus Größen und Getränken.
main.py
from itertools import accumulate, batched, chain, groupby, islice, product
morning = [("Ada", "tea"), ("Ben", "coffee"), ("Cy", "tea")]
evening = [("Dee", "coffee"), ("Eve", "tea")]
orders = list(chain(morning, evening))
print("first two:", list(islice(orders, 2)))
def drink(order: tuple[str, str]) -> str:
return order[1]
for name, group in groupby(sorted(orders, key=drink), key=drink):
print(name, [who for who, _ in group])
cups = [3, 5, 2, 4]
print("running total:", list(accumulate(cups)))
print("tables:", list(batched(["T1", "T2", "T3", "T4", "T5"], 2)))
sizes = ["small", "large"]
print("menu:", [f"{s} {d}" for s, d in product(sizes, ["tea", "coffee"])])
Ausführen mit
python main.pyAusgabe
first two: [('Ada', 'tea'), ('Ben', 'coffee')]
coffee ['Ben', 'Dee']
tea ['Ada', 'Cy', 'Eve']
running total: [3, 8, 10, 14]
tables: [('T1', 'T2'), ('T3', 'T4'), ('T5',)]
menu: ['small tea', 'small coffee', 'large tea', 'large coffee']Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
Übung 1 von 3
group_by_first_letter(words) liefert ein Dict, das jedem Anfangsbuchstaben die Wörter zuordnet, die mit ihm beginnen, jede Liste alphabetisch. Der Starter verwendet groupby ohne Sortieren und funktioniert darum nur mit schon sortierten Eingaben. Korrigieren Sie ihn, sodass ["bat", "apple", "bee", "axe"] {"a": ["apple", "axe"], "b": ["bat", "bee"]} ergibt.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
groupby verbindet nur Nachbarn, gleiche Anfangsbuchstaben müssen also erst nebeneinanderstehen.
Alphabetisch sortierte Wörter sind auch nach dem Anfangsbuchstaben sortiert, und das ist der groupby-Schlüssel.
Schreiben Sie groupby(sorted(words), key=lambda w: w[0]).
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
from itertools import groupby
def group_by_first_letter(words: list[str]) -> dict[str, list[str]]:
"""Map each first letter to the words that start with it."""
result: dict[str, list[str]] = {}
for letter, group in groupby(sorted(words), key=lambda w: w[0]):
result[letter] = list(group)
return result
if __name__ == "__main__":
print(group_by_first_letter(["bat", "apple", "bee", "axe"]))
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
from itertools import groupby
def group_by_first_letter(words: list[str]) -> dict[str, list[str]]:
"""Map each first letter to the words that start with it."""
result: dict[str, list[str]] = {}
for letter, group in groupby(words, key=lambda w: w[0]):
result[letter] = list(group)
return result
if __name__ == "__main__":
print(group_by_first_letter(["bat", "apple", "bee", "axe"]))
test_main.py
from main import group_by_first_letter
def test_sorted_input():
"""Sortierte Eingaben werden gruppiert"""
got = group_by_first_letter(["apple", "axe", "bat"])
assert got == {"a": ["apple", "axe"], "b": ["bat"]}, f"Ergebnis {got!r}"
def test_unsorted_input():
"""Unsortierte Eingaben ergeben einen Eintrag pro Buchstabe, mit jedem Wort"""
got = group_by_first_letter(["bat", "apple", "bee", "axe"])
expected = {"a": ["apple", "axe"], "b": ["bat", "bee"]}
assert got == expected, f"für ['bat', 'apple', 'bee', 'axe'] kam {got!r}, erwartet: {expected!r}"
def test_empty():
"""Ohne Wörter kommt ein leeres Dict"""
got = group_by_first_letter([])
assert got == {}, f"für [] kam {got!r}, erwartet: {{}}"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenÜbung 2 von 3
Schreiben Sie zwei Funktionen mit accumulate. balances(start, changes) liefert den Kontostand vor und nach jeder Änderung: balances(100, [20, -50, 10]) ist [100, 120, 70, 80]. peaks(values) liefert an jeder Position den bisher höchsten Wert: peaks([3, 1, 4, 1, 5]) ist [3, 3, 4, 4, 5]. Beide geben Listen zurück.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
accumulate(changes) allein liefert laufende Summen der Änderungen, ohne den Anfangsstand.
Das Schlüsselwortargument initial=start stellt den Anfangsstand voran und addiert die Änderungen dazu.
Für peaks übergeben Sie max als zweites Argument: accumulate(values, max) behält das Größere aus bisherigem Ergebnis und nächstem Wert.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
from itertools import accumulate
def balances(start: int, changes: list[int]) -> list[int]:
"""Return the balance before and after each change."""
return list(accumulate(changes, initial=start))
def peaks(values: list[int]) -> list[int]:
"""Return the highest value seen so far, at each position."""
return list(accumulate(values, max))
if __name__ == "__main__":
print(balances(100, [20, -50, 10]))
print(peaks([3, 1, 4, 1, 5]))
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
from itertools import accumulate
def balances(start: int, changes: list[int]) -> list[int]:
"""Return the balance before and after each change."""
return [start]
def peaks(values: list[int]) -> list[int]:
"""Return the highest value seen so far, at each position."""
return list(values)
if __name__ == "__main__":
print(balances(100, [20, -50, 10]))
print(peaks([3, 1, 4, 1, 5]))
test_main.py
from main import balances, peaks
def test_balances():
"""100 mit den Änderungen 20, -50 und 10 ergibt 100, 120, 70, 80"""
got = balances(100, [20, -50, 10])
assert got == [100, 120, 70, 80], f"balances(100, [20, -50, 10]) lieferte {got!r}"
def test_no_changes():
"""Ohne Änderungen bleibt nur der Anfangsstand"""
got = balances(5, [])
assert got == [5], f"balances(5, []) lieferte {got!r}, erwartet: [5]"
def test_peaks():
"""peaks([3, 1, 4, 1, 5]) ist [3, 3, 4, 4, 5]"""
got = peaks([3, 1, 4, 1, 5])
assert got == [3, 3, 4, 4, 5], f"peaks([3, 1, 4, 1, 5]) lieferte {got!r}"
def test_peaks_empty():
"""peaks([]) ist []"""
got = peaks([])
assert got == [], f"peaks([]) lieferte {got!r}, erwartet: []"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenÜbung 3 von 3
page(items, size, number) liefert Seite number (ab 1 gezählt) von items als Liste, mit size Elementen pro Seite, oder [], wenn es die Seite nicht gibt. page("abcdefg", 3, 3) ist ["g"]. Es muss mit jedem Iterable funktionieren, auch mit einem Generator. Bilden Sie die Seiten mit batched und springen Sie mit islice zur richtigen.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
batched(items, size) liefert die Seiten als Tupel, eine nach der anderen.
islice(pages, number - 1, None) überspringt die Seiten vor der gesuchten.
next(..., ()) nimmt diese Seite, oder ein leeres Tupel, wenn es keine gibt. Geben Sie sie als Liste zurück.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
from collections.abc import Iterable
from itertools import batched, islice
def page(items: Iterable[str], size: int, number: int) -> list[str]:
"""Return page number (counting from 1), size items per page."""
batch = next(islice(batched(items, size), number - 1, None), ())
return list(batch)
if __name__ == "__main__":
print(page("abcdefg", 3, 2))
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
from collections.abc import Iterable
from itertools import batched, islice
def page(items: Iterable[str], size: int, number: int) -> list[str]:
"""Return page number (counting from 1), size items per page."""
return list(islice(items, size))
if __name__ == "__main__":
print(page("abcdefg", 3, 2))
test_main.py
from main import page
def test_first_page():
"""Seite 1 enthält die ersten drei Buchstaben"""
got = page("abcdefg", 3, 1)
assert got == ["a", "b", "c"], f"page('abcdefg', 3, 1) lieferte {got!r}"
def test_second_page():
"""Seite 2 enthält die nächsten drei"""
got = page("abcdefg", 3, 2)
assert got == ["d", "e", "f"], f"page('abcdefg', 3, 2) lieferte {got!r}, erwartet: ['d', 'e', 'f']"
def test_short_last_page():
"""Die letzte Seite darf kürzer sein"""
got = page("abcdefg", 3, 3)
assert got == ["g"], f"page('abcdefg', 3, 3) lieferte {got!r}, erwartet: ['g']"
def test_no_such_page():
"""Eine Seite hinter dem Ende ist leer"""
got = page("abcdefg", 3, 4)
assert got == [], f"page('abcdefg', 3, 4) lieferte {got!r}, erwartet: []"
def test_generator():
"""Auch ein Generator funktioniert"""
got = page((str(n) for n in range(100)), 10, 2)
expected = [str(n) for n in range(10, 20)]
assert got == expected, f"Seite 2 eines Generators mit 100 Zahlen war {got!r}, erwartet: {expected!r}"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenfrom itertools import islice
scores = [70, 85, 90, 65, 88]
print(list(islice(scores, -2, None)))
Was Python ausgibt
ValueError: Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize.Warum, und die Lösung
islice arbeitet auf Iteratoren, die ihre Länge nicht kennen, vom Ende zu zählen ist also unmöglich. Bei einer Liste schneiden Sie normal: scores[-2:]. Bei einem Datenstrom behält deque(it, maxlen=2) die letzten Elemente; Sie lernen es später in diesem Modul in der Lektion zu collections kennen.
from itertools import chain
names = chain(["Ada", "Ben"], ["Cy"])
print(names[0])
Was Python ausgibt
TypeError: 'itertools.chain' object is not subscriptableWarum, und die Lösung
chain liefert einen Iterator, keine Liste, und hat darum keine Positionen. Nehmen Sie Elemente mit next(names), oder bauen Sie zuerst eine Liste, wenn Sie Indizes brauchen: names = list(chain(...)). Das gilt für jede itertools-Funktion dieser Lektion.
from itertools import batched
for pair in batched("abcde", 2, strict=True):
print(pair)
Was Python ausgibt
ValueError: batched(): incomplete batchWarum, und die Lösung
strict=True verlangt, dass batched ein kurzes letztes Stück ablehnt, und fünf Elemente lassen sich nicht in Paare teilen. Die ersten beiden Paare erscheinen noch vor dem Fehler. Lassen Sie strict weg, wenn ein kürzeres letztes Stück in Ordnung ist, oder prüfen Sie, ob die Länge aufgeht.
Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.