Aufwärmen · Aufgabe 1 von 7
Aufwärmen aus Lektion B3.4: Die Sortierung ist stabil. Was gibt das aus?
units = ["km", "m", "cm"]
print(sorted(units, key=len))// B3.5 · ca. 40 Min. · Einstieg
In diesem Projekt schreiben Sie eine kleine Bibliothek zum Umrechnen: dokumentierte Funktionen für Längen und Temperaturen, ValueError bei falscher Eingabe und ein convert() mit einer Rundungsoption, die nur per Schlüsselwort geht.
Lektion 5 von 5 in B3 Funktionen
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
units = ["km", "m", "cm"]
print(sorted(units, key=len))Vorhersagen · Aufgabe 2 von 7
def check_age(age):
if age < 0:
raise ValueError("age cannot be negative")
return age
print(check_age(30))
print(check_age(-1))
print("done")Üben · Aufgabe 3 von 7
def metres_per(unit):
if unit == "m":
return 1.0
____ ValueError("unknown unit: " + unit)Üben · Aufgabe 4 von 7
Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
print(0.1 + 0.2 == 0.3, round(0.1 + 0.2, 2) == 0.3)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
Das ist das Muster des Projekts, hier für Zeitdauern. seconds_per kennt die Einheiten und löst für jede andere ValueError aus. convert_time prüft den Wert, rechnet über Sekunden und rundet mit einer Option digits, die nur per Schlüsselwort geht und standardmäßig 2 ist. Die def-Zeile ist auf drei Zeilen verteilt, damit sie unter 79 Zeichen bleibt; PEP 8 erlaubt das innerhalb von Klammern.
main.py
def seconds_per(unit: str) -> int:
"""Return how many seconds one unit is."""
if unit == "s":
return 1
elif unit == "min":
return 60
elif unit == "h":
return 3600
elif unit == "d":
return 86400
raise ValueError("unknown time unit: " + unit)
def convert_time(
value: float, from_unit: str, to_unit: str, *, digits: int = 2
) -> float:
"""Convert a duration between units, rounded to digits places."""
if value < 0:
raise ValueError("a duration cannot be negative")
seconds = value * seconds_per(from_unit)
return round(seconds / seconds_per(to_unit), digits)
print(convert_time(90, "min", "h"))
print(convert_time(1, "d", "min"))
print(convert_time(100, "s", "min"))
print(convert_time(100, "s", "min", digits=4))
print(convert_time.__doc__)
Ausführen mit
python main.pyAusgabe
1.5
1440.0
1.67
1.6667
Convert a duration between units, rounded to digits places.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
Beginnen Sie die Bibliothek mit Längen. metres_per(unit) gibt zurück, wie viele Meter eine Einheit sind: mm 0.001, cm 0.01, m 1.0, km 1000.0, und löst für alles andere ValueError("unknown length unit: " + unit) aus. convert_length(value, from_unit, to_unit) löst für einen negativen Wert ValueError aus und rechnet dann über Meter um. Die Tests vergleichen auf 6 Stellen gerundet.
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.
Schreiben Sie metres_per als Kette aus if und elif mit einem return je Einheit, und setzen Sie raise ValueError(…) hinter die Kette.
Prüfen Sie in convert_length zuerst if value < 0: und lösen Sie dann den Fehler aus.
Danach: return value * metres_per(from_unit) / metres_per(to_unit).
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "mm":
return 0.001
elif unit == "cm":
return 0.01
elif unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
if value < 0:
raise ValueError("a length cannot be negative")
return value * metres_per(from_unit) / metres_per(to_unit)
print(convert_length(2.5, "km", "m"))
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
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "m":
return 1.0
# Add mm, cm and km, and raise ValueError for any other unit.
return 1.0
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
# Raise ValueError for a negative value, then convert via metres.
return value
print(convert_length(2.5, "km", "m"))
test_main.py
from main import convert_length
def test_km_to_m():
"""2.5 km sind 2500 m"""
got = convert_length(2.5, "km", "m")
assert round(got, 6) == 2500.0, f"convert_length(2.5, 'km', 'm') lieferte {got!r}, erwartet: 2500.0"
def test_cm_to_m():
"""250 cm sind 2.5 m"""
got = convert_length(250, "cm", "m")
assert round(got, 6) == 2.5, f"convert_length(250, 'cm', 'm') lieferte {got!r}, erwartet: 2.5"
def test_mm_to_cm():
"""5 mm sind 0.5 cm"""
got = convert_length(5, "mm", "cm")
assert round(got, 6) == 0.5, f"convert_length(5, 'mm', 'cm') lieferte {got!r}, erwartet: 0.5"
def test_same_unit():
"""7 m sind 7 m"""
got = convert_length(7, "m", "m")
assert round(got, 6) == 7.0, f"convert_length(7, 'm', 'm') lieferte {got!r}, erwartet: 7.0"
def test_unknown_unit():
"""Eine unbekannte Einheit löst ValueError aus"""
try:
got = convert_length(3, "m", "miles")
except ValueError:
return
raise AssertionError(f"convert_length(3, 'm', 'miles') lieferte {got!r} statt einen ValueError auszulösen")
def test_negative_length():
"""Eine negative Länge löst ValueError aus"""
try:
got = convert_length(-1, "m", "cm")
except ValueError:
return
raise AssertionError(f"convert_length(-1, 'm', 'cm') lieferte {got!r} statt einen ValueError auszulösen")
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
Ergänzen Sie Temperaturen in "C", "F" und "K". Schreiben Sie to_kelvin(value, unit) und from_kelvin(kelvin, unit): K = C + 273.15 und C = (F - 32) * 5 / 9. Beide lösen für eine unbekannte Einheit ValueError aus. convert_temperature(value, from_unit, to_unit) rechnet in Kelvin um, löst unter 0 K ValueError aus und rechnet von Kelvin in die Zieleinheit. Schritt 1 steht schon in main.py.
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.
to_kelvin: K gibt value zurück, C gibt value + 273.15, F gibt (value - 32) * 5 / 9 + 273.15, alles andere löst den Fehler aus.
from_kelvin kehrt das um: C ist kelvin - 273.15, F ist (kelvin - 273.15) * 9 / 5 + 32.
convert_temperature: kelvin = to_kelvin(value, from_unit); if kelvin < 0: raise ValueError(…); return from_kelvin(kelvin, to_unit).
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "mm":
return 0.001
elif unit == "cm":
return 0.01
elif unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
if value < 0:
raise ValueError("a length cannot be negative")
return value * metres_per(from_unit) / metres_per(to_unit)
TEMPERATURE_UNITS = ["C", "F", "K"]
def to_kelvin(value: float, unit: str) -> float:
"""Return the temperature in kelvin."""
if unit == "K":
return value
elif unit == "C":
return value + 273.15
elif unit == "F":
return (value - 32) * 5 / 9 + 273.15
raise ValueError("unknown temperature unit: " + unit)
def from_kelvin(kelvin: float, unit: str) -> float:
"""Return a temperature given in kelvin in another unit."""
if unit == "K":
return kelvin
elif unit == "C":
return kelvin - 273.15
elif unit == "F":
return (kelvin - 273.15) * 9 / 5 + 32
raise ValueError("unknown temperature unit: " + unit)
def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature between C, F and K."""
kelvin = to_kelvin(value, from_unit)
if kelvin < 0:
raise ValueError("below absolute zero")
return from_kelvin(kelvin, to_unit)
print(convert_temperature(100, "C", "F"))
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
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "mm":
return 0.001
elif unit == "cm":
return 0.01
elif unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
if value < 0:
raise ValueError("a length cannot be negative")
return value * metres_per(from_unit) / metres_per(to_unit)
TEMPERATURE_UNITS = ["C", "F", "K"]
def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature between C, F and K."""
# Step 2: convert to kelvin first, refuse anything below 0 K,
# then convert from kelvin to the target unit.
return value
print(convert_temperature(100, "C", "F"))
test_main.py
from main import convert_temperature
def test_c_to_f():
"""100 C sind 212 F"""
got = convert_temperature(100, "C", "F")
assert round(got, 6) == 212.0, f"convert_temperature(100, 'C', 'F') lieferte {got!r}, erwartet: 212.0"
def test_f_to_c():
"""32 F sind 0 C"""
got = convert_temperature(32, "F", "C")
assert round(got, 6) == 0.0, f"convert_temperature(32, 'F', 'C') lieferte {got!r}, erwartet: 0.0"
def test_kelvin():
"""0 C sind 273.15 K, und 0 K sind -273.15 C"""
got = convert_temperature(0, "C", "K"), convert_temperature(0, "K", "C")
assert (round(got[0], 6), round(got[1], 6)) == (273.15, -273.15), f"convert_temperature(0, 'C', 'K') und convert_temperature(0, 'K', 'C') lieferten {got!r}"
def test_minus_forty():
"""-40 C sind -40 F"""
got = convert_temperature(-40, "C", "F")
assert round(got, 6) == -40.0, f"convert_temperature(-40, 'C', 'F') lieferte {got!r}, erwartet: -40.0"
def test_below_absolute_zero():
"""-300 C und -1 K lösen ValueError aus"""
for value, unit in [(-300, "C"), (-1, "K")]:
try:
got = convert_temperature(value, unit, "F")
except ValueError:
continue
raise AssertionError(f"convert_temperature({value}, {unit!r}, 'F') lieferte {got!r} statt einen ValueError auszulösen")
def test_unknown_unit():
"""Eine unbekannte Einheit löst ValueError aus"""
try:
got = convert_temperature(20, "C", "X")
except ValueError:
return
raise AssertionError(f"convert_temperature(20, 'C', 'X') lieferte {got!r} statt einen ValueError auszulösen")
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
Vollenden Sie die Bibliothek mit convert(value, from_unit, to_unit, *, digits=None). Stehen beide Einheiten in LENGTH_UNITS, nutzen Sie convert_length; stehen beide in TEMPERATURE_UNITS, nutzen Sie convert_temperature; sonst lösen Sie ValueError("cannot convert " + from_unit + " to " + to_unit) aus. Ist digits nicht None, runden Sie das Ergebnis. Annotieren Sie digits als int | None, und geben Sie convert einen Docstring.
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.
from_unit in LENGTH_UNITS ist True, wenn die Einheit in der Liste steht; verbinden Sie zwei solche Tests mit and.
Speichern Sie das Ergebnis von convert_length oder convert_temperature in einer Variablen, und lösen Sie im else-Zweig ValueError aus.
Ergänzen Sie *, digits: int | None = None in den Parametern, dann: if digits is not None: result = round(result, digits).
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "mm":
return 0.001
elif unit == "cm":
return 0.01
elif unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
if value < 0:
raise ValueError("a length cannot be negative")
return value * metres_per(from_unit) / metres_per(to_unit)
TEMPERATURE_UNITS = ["C", "F", "K"]
def to_kelvin(value: float, unit: str) -> float:
"""Return the temperature in kelvin."""
if unit == "K":
return value
elif unit == "C":
return value + 273.15
elif unit == "F":
return (value - 32) * 5 / 9 + 273.15
raise ValueError("unknown temperature unit: " + unit)
def from_kelvin(kelvin: float, unit: str) -> float:
"""Return a temperature given in kelvin in another unit."""
if unit == "K":
return kelvin
elif unit == "C":
return kelvin - 273.15
elif unit == "F":
return (kelvin - 273.15) * 9 / 5 + 32
raise ValueError("unknown temperature unit: " + unit)
def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature between C, F and K."""
kelvin = to_kelvin(value, from_unit)
if kelvin < 0:
raise ValueError("below absolute zero")
return from_kelvin(kelvin, to_unit)
def convert(
value: float, from_unit: str, to_unit: str, *, digits: int | None = None
) -> float:
"""Convert value between two units of the same kind.
Lengths: mm, cm, m, km. Temperatures: C, F, K. With digits,
the result is rounded to that many decimal places.
"""
if from_unit in LENGTH_UNITS and to_unit in LENGTH_UNITS:
result = convert_length(value, from_unit, to_unit)
elif from_unit in TEMPERATURE_UNITS and to_unit in TEMPERATURE_UNITS:
result = convert_temperature(value, from_unit, to_unit)
else:
raise ValueError("cannot convert " + from_unit + " to " + to_unit)
if digits is not None:
result = round(result, digits)
return result
print(convert(1, "km", "m"))
print(convert(100, "C", "F", digits=1))
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
LENGTH_UNITS = ["mm", "cm", "m", "km"]
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "mm":
return 0.001
elif unit == "cm":
return 0.01
elif unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
if value < 0:
raise ValueError("a length cannot be negative")
return value * metres_per(from_unit) / metres_per(to_unit)
TEMPERATURE_UNITS = ["C", "F", "K"]
def to_kelvin(value: float, unit: str) -> float:
"""Return the temperature in kelvin."""
if unit == "K":
return value
elif unit == "C":
return value + 273.15
elif unit == "F":
return (value - 32) * 5 / 9 + 273.15
raise ValueError("unknown temperature unit: " + unit)
def from_kelvin(kelvin: float, unit: str) -> float:
"""Return a temperature given in kelvin in another unit."""
if unit == "K":
return kelvin
elif unit == "C":
return kelvin - 273.15
elif unit == "F":
return (kelvin - 273.15) * 9 / 5 + 32
raise ValueError("unknown temperature unit: " + unit)
def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature between C, F and K."""
kelvin = to_kelvin(value, from_unit)
if kelvin < 0:
raise ValueError("below absolute zero")
return from_kelvin(kelvin, to_unit)
def convert(value: float, from_unit: str, to_unit: str) -> float:
"""Convert value between two units of the same kind."""
# Step 3: pick convert_length or convert_temperature, refuse mixed
# kinds, and add a keyword-only option digits for rounding.
return value
print(convert(1, "km", "m"))
test_main.py
from main import convert
def test_length():
"""convert(1, "km", "m") ist 1000"""
got = convert(1, "km", "m")
assert round(got, 6) == 1000.0, f"convert(1, 'km', 'm') lieferte {got!r}, erwartet: 1000.0"
def test_temperature():
"""convert(100, "C", "F") ist 212"""
got = convert(100, "C", "F")
assert round(got, 6) == 212.0, f"convert(100, 'C', 'F') lieferte {got!r}, erwartet: 212.0"
def test_digits():
"""digits=1 rundet 123.456 cm auf 123.5"""
got = convert(1.23456, "m", "cm", digits=1)
assert got == 123.5, f"convert(1.23456, 'm', 'cm', digits=1) lieferte {got!r}, erwartet: 123.5"
def test_mixed_kinds():
"""Eine Länge wird keine Temperatur"""
try:
got = convert(1, "m", "C")
except ValueError:
return
raise AssertionError(f"convert(1, 'm', 'C') lieferte {got!r} statt einen ValueError auszulösen")
def test_digits_keyword_only():
"""digits muss per Schlüsselwort kommen"""
try:
got = convert(1.23456, "m", "cm", 1)
except TypeError:
return
raise AssertionError(f"convert(1.23456, 'm', 'cm', 1) lieferte {got!r}; digits sollte nur per Schlüsselwort gehen")
def test_docstring():
"""convert hat einen Docstring"""
assert convert.__doc__, "convert hat keinen Docstring"
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 herunterladendef metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "m":
return 1.0
elif unit == "km":
return 1000.0
raise ValueError("unknown length unit: " + unit)
def convert_length(value: float, from_unit: str, to_unit: str) -> float:
"""Convert a length from one unit to another."""
return value * metres_per(from_unit) / metres_per(to_unit)
print(convert_length(3, "m", "miles"))
Was Python ausgibt
ValueError: unknown length unit: milesWarum, und die Lösung
Hier arbeitet die Prüfung wie gewollt: Der Traceback führt vom Aufruf bis zur raise-Zeile in metres_per, und die letzte Zeile trägt Ihre Meldung. Korrigieren Sie den Aufruf, oder ergänzen Sie die Einheit in metres_per. Eine Meldung, die den falschen Wert nennt, macht die Suche kurz.
def convert(value: float, factor: float, *, digits: int = 2) -> float:
"""Multiply value by factor and round the result."""
return round(value * factor, digits)
print(convert(1.23456, 100, 0))
Was Python ausgibt
TypeError: convert() takes 2 positional arguments but 3 were givenWarum, und die Lösung
digits steht hinter dem * und muss genannt werden: convert(1.23456, 100, digits=0). Genau darum geht es bei solchen Optionen: Eine nackte 0 im Aufruf sagt nichts darüber, was sie steuert.
def metres_per(unit: str) -> float:
"""Return how many metres one unit is."""
if unit == "m":
return 1.0
raise "unknown length unit: " + unit
print(metres_per("ft"))
Was Python ausgibt
TypeError: exceptions must derive from BaseExceptionWarum, und die Lösung
raise braucht eine Ausnahme, keinen einfachen String. Verpacken Sie die Meldung: raise ValueError("unknown length unit: " + unit). mypy meldet diesen Fehler schon, bevor das Programm läuft.
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.