From 60cf2dd6c6c738229cef73dc20ffe9ea78ecc29c Mon Sep 17 00:00:00 2001 From: zimmersandro Date: Fri, 13 Mar 2026 17:44:37 +0100 Subject: [PATCH] feat: module and import exercises --- .../modules_imports/examples/ex1/main.py | 33 +++++++++++ .../examples/ex1/src/__init__.py | 0 .../examples/ex1/src/geometrie.py | 14 +++++ .../examples/ex1/src/mathematik.py | 14 +++++ .../modules_imports/examples/ex2/main.py | 59 +++++++++++++++++++ .../examples/ex2/src/__init__.py | 0 .../examples/ex2/src/formatierung.py | 21 +++++++ .../examples/ex2/src/statistik.py | 30 ++++++++++ .../examples/ex3/custom_random.py | 27 +++++++++ .../modules_imports/examples/ex3/main.py | 51 ++++++++++++++++ .../modules_imports/examples/ex3/statistik.py | 20 +++++++ .../modules_imports/examples/ex3/ziehung.py | 19 ++++++ .../modules_imports/examples/ex4/main.py | 53 +++++++++++++++++ .../examples/ex4/notenrechner.py | 16 +++++ .../examples/ex4/src/__init__.py | 0 .../modules_imports/examples/ex4/src/kurs.py | 35 +++++++++++ .../examples/ex4/src/schueler.py | 28 +++++++++ 17 files changed, 420 insertions(+) create mode 100644 src/tutorial/modules_imports/examples/ex1/main.py create mode 100644 src/tutorial/modules_imports/examples/ex1/src/__init__.py create mode 100644 src/tutorial/modules_imports/examples/ex1/src/geometrie.py create mode 100644 src/tutorial/modules_imports/examples/ex1/src/mathematik.py create mode 100644 src/tutorial/modules_imports/examples/ex2/main.py create mode 100644 src/tutorial/modules_imports/examples/ex2/src/__init__.py create mode 100644 src/tutorial/modules_imports/examples/ex2/src/formatierung.py create mode 100644 src/tutorial/modules_imports/examples/ex2/src/statistik.py create mode 100644 src/tutorial/modules_imports/examples/ex3/custom_random.py create mode 100644 src/tutorial/modules_imports/examples/ex3/main.py create mode 100644 src/tutorial/modules_imports/examples/ex3/statistik.py create mode 100644 src/tutorial/modules_imports/examples/ex3/ziehung.py create mode 100644 src/tutorial/modules_imports/examples/ex4/main.py create mode 100644 src/tutorial/modules_imports/examples/ex4/notenrechner.py create mode 100644 src/tutorial/modules_imports/examples/ex4/src/__init__.py create mode 100644 src/tutorial/modules_imports/examples/ex4/src/kurs.py create mode 100644 src/tutorial/modules_imports/examples/ex4/src/schueler.py diff --git a/src/tutorial/modules_imports/examples/ex1/main.py b/src/tutorial/modules_imports/examples/ex1/main.py new file mode 100644 index 0000000..f834a50 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex1/main.py @@ -0,0 +1,33 @@ +# Ziel dieses Skripts: +# +# 1. Das Produkt von 6 * 7 berechnen → Erwartet: 42.0 +# 2. Die Kreisfläche für Radius 5 berechnen → Erwartet: ~78.54 +# 3. Den genauen Wert von PI ausgeben → Erwartet: 3.141592653589793 +# +# ---------------------------------------------------------------------- +# AUFGABE: Das Skript liefert falsche Ergebnisse. Finde den Fehler und +# korrigiere die Import-Anweisungen – ohne den restlichen Code +# zu verändern! +# ---------------------------------------------------------------------- + +# from src.mathematik import berechne, PI # (1) Import aus mathematik +# from src.geometrie import berechne, PI # (2) Import aus geometrie +import src.geometrie as geo +import src.mathematik as mathe + + +def main(): + # --- Aufgabe 1: Produkt berechnen (nutzt mathematik.berechne) --- + produkt = mathe.berechne(6, 7) # Erwartet: 42.0 — bekommt aber einen Fehler! + print(f"6 × 7 = {produkt}") + + # --- Aufgabe 2: Kreisfläche (nutzt geometrie.berechne) --- + flaeche = geo.berechne(5) # Erwartet: ~78.54 + print(f"Kreisfläche (r=5): {flaeche:.4f}") + + # --- Aufgabe 3: PI-Wert --- + print(f"PI = {mathe.PI}") # Erwartet: 3.141592653589793 + + +if __name__ == "__main__": + main() diff --git a/src/tutorial/modules_imports/examples/ex1/src/__init__.py b/src/tutorial/modules_imports/examples/ex1/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tutorial/modules_imports/examples/ex1/src/geometrie.py b/src/tutorial/modules_imports/examples/ex1/src/geometrie.py new file mode 100644 index 0000000..1957b29 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex1/src/geometrie.py @@ -0,0 +1,14 @@ +# geometrie.py +# Modul für geometrische Berechnungen (Kreisflächen, Umfang usw.) + +PI = 3.14 # Vereinfachter Wert (nur 2 Nachkommastellen!) + + +def berechne(radius: float) -> float: + """Berechnet die Fläche eines Kreises: A = PI * r²""" + return PI * radius**2 + + +def umfang(radius: float) -> float: + """Berechnet den Umfang eines Kreises: U = 2 * PI * r""" + return 2 * PI * radius diff --git a/src/tutorial/modules_imports/examples/ex1/src/mathematik.py b/src/tutorial/modules_imports/examples/ex1/src/mathematik.py new file mode 100644 index 0000000..89b4353 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex1/src/mathematik.py @@ -0,0 +1,14 @@ +# mathematik.py +# Modul für allgemeine mathematische Berechnungen + +PI = 3.141592653589793 # Hochpräziser Wert + + +def berechne(a: float, b: float) -> float: + """Berechnet das Produkt zweier Zahlen.""" + return a * b + + +def potenz(basis: float, exponent: int) -> float: + """Berechnet basis hoch exponent.""" + return basis**exponent diff --git a/src/tutorial/modules_imports/examples/ex2/main.py b/src/tutorial/modules_imports/examples/ex2/main.py new file mode 100644 index 0000000..01629fe --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex2/main.py @@ -0,0 +1,59 @@ +# Ziel dieses Skripts: +# +# Testergebnisse einer Klasse auswerten und formatiert ausgeben. +# +# Gegeben: Punkte von 5 Studierenden (von max. 100 Punkten) +# Erwartet: +# Mittelwert → 73.5 (kaufm. gerundet → 74 → "Gut") +# Max. Punkte → 100 (aus statistik.MAX_WERT) +# +# ---------------------------------------------------------------------- +# AUFGABE: Das Skript gibt falsche Werte aus. Es gibt keine Fehlermeldung +# vom Interpreter. Finde heraus, warum die Ergebnisse falsch sind +# und korrigiere die Import-Anweisungen! +# ---------------------------------------------------------------------- + +from src.statistik import ( + runde, + mittelwert, + bewerte, + MAX_WERT, +) # importiert: runde, mittelwert, bewerte, MAX_WERT, MIN_WERT +from src.formatierung import ( + trennlinie, +) # importiert: runde, als_prozent, trennlinie, MAX_WERT, MIN_WERT + +PUNKTE = [92, 85, 61, 48, 82] + + +def auswertung(): + print(trennlinie("=")) + print(" TESTERGEBNISSE") + print(trennlinie("=")) + + # --- Mittelwert berechnen und benoten --- + mw = mittelwert(PUNKTE) + mw_gerundet = runde(mw) # Soll kaufm. auf int runden → Erwartet: 74 + note = bewerte(mw) + + print(f" Mittelwert : {mw}") + print(f" Gerundet : {mw_gerundet} ← Erwartet: 74 (int)") + print(f" Durchschnittsnote: {note}") + + print(trennlinie()) + + # --- Maximale Punktzahl aus dem Modul --- + print(f" Max. Punkte : {MAX_WERT} ← Erwartet: 100") + + print(trennlinie()) + + # --- Einzelne Ergebnisse --- + print(" Einzelergebnisse:") + for p in PUNKTE: + print(f" {p:>3} Punkte → {bewerte(p)}") + + print(trennlinie("=")) + + +if __name__ == "__main__": + auswertung() diff --git a/src/tutorial/modules_imports/examples/ex2/src/__init__.py b/src/tutorial/modules_imports/examples/ex2/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tutorial/modules_imports/examples/ex2/src/formatierung.py b/src/tutorial/modules_imports/examples/ex2/src/formatierung.py new file mode 100644 index 0000000..20c88d6 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex2/src/formatierung.py @@ -0,0 +1,21 @@ +# formatierung.py +# Modul für Ausgabe-Formatierung und Darstellung + +MAX_WERT = 255 # Maximaler RGB-Farbwert (0–255) +MIN_WERT = 0 # Minimaler RGB-Farbwert + + +def runde(wert: float, stellen: int = 2) -> float: + """Rundet auf 'stellen' Nachkommastellen (für Anzeige-Formatierung).""" + faktor = 10**stellen + return int(wert * faktor + 0.5) / faktor + + +def als_prozent(wert: float, gesamt: float) -> str: + """Gibt einen Wert als formatierten Prozentstring zurück.""" + return f"{runde(wert / gesamt * 100)} %" + + +def trennlinie(zeichen: str = "-", laenge: int = 40) -> str: + """Erzeugt eine Trennlinie für die Konsolenausgabe.""" + return zeichen * laenge diff --git a/src/tutorial/modules_imports/examples/ex2/src/statistik.py b/src/tutorial/modules_imports/examples/ex2/src/statistik.py new file mode 100644 index 0000000..c55e0e7 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex2/src/statistik.py @@ -0,0 +1,30 @@ +# statistik.py +# Modul für statistische Berechnungen + +MAX_WERT = 100 # Maximale Punktzahl in einem Test (0–100) +MIN_WERT = 0 # Minimale Punktzahl + + +def runde(wert: float) -> int: + """Rundet kaufmännisch auf ganze Zahlen (für Testergebnisse).""" + return int(wert + 0.5) + + +def mittelwert(werte: list[float]) -> float: + """Berechnet den arithmetischen Mittelwert einer Liste.""" + return sum(werte) / len(werte) + + +def bewerte(punkte: float) -> str: + """Gibt eine Note zurück basierend auf Punktzahl (0–100).""" + p = runde(punkte) + if p >= 90: + return "Sehr gut" + elif p >= 75: + return "Gut" + elif p >= 60: + return "Befriedigend" + elif p >= 45: + return "Ausreichend" + else: + return "Ungenügend" diff --git a/src/tutorial/modules_imports/examples/ex3/custom_random.py b/src/tutorial/modules_imports/examples/ex3/custom_random.py new file mode 100644 index 0000000..835004c --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex3/custom_random.py @@ -0,0 +1,27 @@ +# random.py +# +# Dieses Modul wurde angelegt, um eigene Hilfsfunktionen für +# "Zufallsentscheidungen" in der Lotterie-Logik bereitzustellen. +# +# Es definiert einige der gleichen Funktionen wie das Standardmodul – +# aber mit vereinfachter (fehlerhafter) Implementierung. + + +def randint(a: int, b: int) -> int: + """Gibt eine 'zufällige' Ganzzahl zwischen a und b zurück.""" + return a # ← gibt IMMER den kleinsten Wert zurück! + + +def shuffle(lst: list) -> None: + """Mischt eine Liste in-place.""" + pass # ← tut gar nichts! + + +def sample(population: list, k: int) -> list: + """Gibt k zufällige Elemente aus population zurück.""" + return list(population)[:k] # ← gibt IMMER die ersten k Elemente zurück! + + +def seed(a=None): + """Setzt den Zufallsgenerator-Seed.""" + pass # ← keine Wirkung diff --git a/src/tutorial/modules_imports/examples/ex3/main.py b/src/tutorial/modules_imports/examples/ex3/main.py new file mode 100644 index 0000000..8241251 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex3/main.py @@ -0,0 +1,51 @@ +# Lotterie-Simulation: Zieht 6 aus 45 Zahlen, dazu eine Zusatzzahl. +# +# Wiederholt die Ziehung 5× und gibt die Ergebnisse aus. +# Anschließend wird die Gewinnerliste zufällig gemischt. +# +# Erwartetes Verhalten: +# • Jede Ziehung liefert 6 VERSCHIEDENE, ZUFÄLLIGE Zahlen aus 1–45 +# • Wiederholte Aufrufe liefern UNTERSCHIEDLICHE Ergebnisse +# • Die Teilnehmerliste ist nach dem Mischen in ZUFÄLLIGER Reihenfolge +# +# ---------------------------------------------------------------------- +# AUFGABE: Das Programm läuft ohne Fehlermeldung, aber die Ergebnisse +# sind offensichtlich nicht zufällig. Finde die Ursache und +# behebe den Fehler – ohne ziehung.py oder statistik.py zu ändern! +# +# REMARK: Möglicherweise ist das Problem sogar abhängig von der verwendeten +# IDE... Lasst das main.py mal aus eurer IDE laufen sowie aus dem +# Terminal. Sind die Resultate gleich? +# ---------------------------------------------------------------------- + +from ziehung import ziehe_zahlen, ziehe_zusatzzahl +from statistik import simuliere_ziehungen, mische_teilnehmer + +TEILNEHMER = ["Alice", "Bob", "Carol", "Dave", "Eve"] + + +def main(): + print("=" * 45) + print(" LOTTO-SIMULATION (6 aus 45)") + print("=" * 45) + + print("\n--- 5 unabhängige Ziehungen ---") + for i, ziehung in enumerate(simuliere_ziehungen(5), 1): + print(f" Ziehung {i}: {ziehung}") + + print("\n--- Einzelziehung mit Zusatzzahl ---") + haupt = ziehe_zahlen() + zusatz = ziehe_zusatzzahl(haupt) + print(f" Hauptzahlen : {haupt}") + print(f" Zusatzzahl : {zusatz}") + + print("\n--- Gewinnerliste (zufällig gemischt) ---") + gemischt = mische_teilnehmer(TEILNEHMER) + for rang, name in enumerate(gemischt, 1): + print(f" Rang {rang}: {name}") + + print("=" * 45) + + +if __name__ == "__main__": + main() diff --git a/src/tutorial/modules_imports/examples/ex3/statistik.py b/src/tutorial/modules_imports/examples/ex3/statistik.py new file mode 100644 index 0000000..c94b20e --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex3/statistik.py @@ -0,0 +1,20 @@ +# Wertet mehrere Lottoziehungen statistisch aus + +import custom_random +from ziehung import ziehe_zahlen + + +def simuliere_ziehungen(anzahl: int = 10) -> list[list[int]]: + """Führt 'anzahl' unabhängige Lottoziehungen durch.""" + ergebnisse = [] + for _ in range(anzahl): + zahlen = ziehe_zahlen() + ergebnisse.append(zahlen) + return ergebnisse + + +def mische_teilnehmer(teilnehmer: list[str]) -> list[str]: + """Mischt die Teilnehmerliste zufällig (z. B. für Gewinner-Reihenfolge).""" + kopie = teilnehmer[:] + custom_random.shuffle(kopie) + return kopie diff --git a/src/tutorial/modules_imports/examples/ex3/ziehung.py b/src/tutorial/modules_imports/examples/ex3/ziehung.py new file mode 100644 index 0000000..afd9275 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex3/ziehung.py @@ -0,0 +1,19 @@ +# lotterie/ziehung.py +# Modul für die eigentliche Lottoziehung + +import custom_random + +ZAHLEN_POOL = list(range(1, 46)) # Zahlen 1–45 + + +def ziehe_zahlen(anzahl: int = 6) -> list[int]: + """Zieht 'anzahl' verschiedene Lottozahlen aus dem Pool.""" + gezogen = custom_random.sample(ZAHLEN_POOL, anzahl) + gezogen.sort() + return gezogen + + +def ziehe_zusatzzahl(ausgeschlossen: list[int]) -> int: + """Zieht eine Zusatzzahl, die nicht in der Hauptziehung vorkommt.""" + pool = [z for z in ZAHLEN_POOL if z not in ausgeschlossen] + return custom_random.randint(1, len(pool) - 1) # ← Index in pool, dann Lookup diff --git a/src/tutorial/modules_imports/examples/ex4/main.py b/src/tutorial/modules_imports/examples/ex4/main.py new file mode 100644 index 0000000..d12ef85 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex4/main.py @@ -0,0 +1,53 @@ +# Schulverwaltungs-Simulation: +# • Drei Schüler werden angelegt (mit Noten in zwei Kursen) +# • Zwei Kurse werden erstellt, Schüler werden eingeschrieben +# • Notenspiegel je Schüler und Kursbericht je Kurs wird ausgegeben +# +# ---------------------------------------------------------------------- +# AUFGABE: Das Programm lässt sich gar nicht erst starten – es gibt +# sofort einen ImportError. +# +# 1. Lies die Fehlermeldung sorgfältig und zeichne den +# Importgraphen auf: Welches Modul importiert welches? +# +# 2. Versuche durch eine geeignete Gegenmassnahme den Fehler zu +# beheben. +# ---------------------------------------------------------------------- + +from src.kurs import Kurs +from src.schueler import Schueler + + +def main(): + # --- Schüler anlegen --- + anna = Schueler("Anna Meier", {"Mathematik": 2.5, "Deutsch": 3.0}) + ben = Schueler("Ben Keller", {"Mathematik": 5.0, "Deutsch": 2.0}) + clara = Schueler("Clara Huber", {"Mathematik": 3.5, "Deutsch": 4.5}) + + # --- Kurse anlegen und Schüler einschreiben --- + mathe = Kurs("Mathematik") + deutsch = Kurs("Deutsch") + + for s in [anna, ben, clara]: + mathe.einschreiben(s) + deutsch.einschreiben(s) + + # --- Ausgabe Notenspiegel --- + print("=" * 45) + print(" NOTENSPIEGEL") + print("=" * 45) + for s in [anna, ben, clara]: + print(s.notenspiegel()) + print() + + # --- Ausgabe Kursberichte --- + print("=" * 45) + print(" KURSBERICHTE") + print("=" * 45) + print(mathe.kursbericht()) + print(deutsch.kursbericht()) + print("=" * 45) + + +if __name__ == "__main__": + main() diff --git a/src/tutorial/modules_imports/examples/ex4/notenrechner.py b/src/tutorial/modules_imports/examples/ex4/notenrechner.py new file mode 100644 index 0000000..6e49fee --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex4/notenrechner.py @@ -0,0 +1,16 @@ +# --------------------------------------------------------------- +# Gemeinsam genutzte Hilfsfunktion – wird auch in schueler.py +# über den Import von oben verwendet. +# --------------------------------------------------------------- + + +def ist_bestanden(note: float) -> bool: + """Gibt True zurück, wenn die Note ≤ 4.0 (bestanden) ist.""" + return note <= 4.0 + + +def berechne_klassendurchschnitt(noten: list[float]) -> float: + """Berechnet den Notendurchschnitt einer Gruppe.""" + if not noten: + return 0.0 + return round(sum(noten) / len(noten), 2) diff --git a/src/tutorial/modules_imports/examples/ex4/src/__init__.py b/src/tutorial/modules_imports/examples/ex4/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tutorial/modules_imports/examples/ex4/src/kurs.py b/src/tutorial/modules_imports/examples/ex4/src/kurs.py new file mode 100644 index 0000000..d2c7a1d --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex4/src/kurs.py @@ -0,0 +1,35 @@ +# schulverwaltung/kurs.py +# +# Verwaltet Kurse und eingeschriebene Schüler. +# Benötigt die Schueler-Klasse aus schueler.py für die Einschreibung +# und Notenauswertung. + +from notenrechner import ist_bestanden, berechne_klassendurchschnitt +from .schueler import Schueler + + +class Kurs: + def __init__(self, name: str): + self.name = name + self.schueler: list[Schueler] = [] + + def einschreiben(self, schueler: Schueler) -> None: + """Schreibt einen Schüler in diesen Kurs ein.""" + self.schueler.append(schueler) + + def kursbericht(self) -> str: + """Gibt eine Übersicht über alle Schüler und den Kursdurchschnitt aus.""" + zeilen = [f"\n Kurs: {self.name} ({len(self.schueler)} Schüler)"] + noten_im_kurs = [] + + for s in self.schueler: + note = s.noten.get(self.name) + if note is not None: + status = "✓" if ist_bestanden(note) else "✗" + zeilen.append(f" {status} {s.name:<20} {note:.1f}") + noten_im_kurs.append(note) + + if noten_im_kurs: + schnitt = berechne_klassendurchschnitt(noten_im_kurs) + zeilen.append(f" → Klassendurchschnitt: {schnitt:.2f}") + return "\n".join(zeilen) diff --git a/src/tutorial/modules_imports/examples/ex4/src/schueler.py b/src/tutorial/modules_imports/examples/ex4/src/schueler.py new file mode 100644 index 0000000..81209f9 --- /dev/null +++ b/src/tutorial/modules_imports/examples/ex4/src/schueler.py @@ -0,0 +1,28 @@ +# Verwaltet Schüler-Daten und prüft den Abschlussstatus. +# Benötigt ist_bestanden() aus kurs.py, um festzustellen ob +# ein Schüler alle Kurse bestanden hat. + +from notenrechner import ist_bestanden + + +class Schueler: + def __init__(self, name: str, noten: dict[str, float]): + """ + name : Vollständiger Name des Schülers + noten : {Kursname: Note} z. B. {'Mathematik': 4.5, 'Deutsch': 3.0} + """ + self.name = name + self.noten = noten + + def kann_abschliessen(self) -> bool: + """Gibt True zurück, wenn alle Kursnoten bestanden sind (Note ≤ 4.0).""" + return all(ist_bestanden(note) for note in self.noten.values()) + + def notenspiegel(self) -> str: + """Gibt eine formatierte Übersicht aller Noten zurück.""" + zeilen = [f" Schüler: {self.name}"] + for kurs, note in self.noten.items(): + status = "✓" if ist_bestanden(note) else "✗" + zeilen.append(f" {status} {kurs:<18} Note: {note:.1f}") + zeilen.append(f" → Abschluss möglich: {self.kann_abschliessen()}") + return "\n".join(zeilen)