Implementiere Lehrpfad 1 Grundlagen (G01 bis G10) und erstelle 3-Lehrpfad-System im Lernportal
This commit is contained in:
parent
0a32dadcc4
commit
a3a6362c77
54 changed files with 8022 additions and 147 deletions
120
LEHRPLAN.md
120
LEHRPLAN.md
|
|
@ -1,73 +1,77 @@
|
|||
# 📚 Didaktischer Lehrplan & Abgleich mit dem Schulskriptum
|
||||
# 📚 Didaktischer Lehrplan: Das 3-Säulen-System
|
||||
|
||||
Dieses Dokument dient als didaktischer Leitfaden für die Python-Nachhilfe.
|
||||
Es gleicht die Übungsreihe mit dem offiziellen Lehrplan und Skriptum des Lehrers (**`rradlbauer/python_skriptum`**) ab.
|
||||
Es gleicht die gesamte Übungsreihe (Grundlagen & Fortgeschrittene Objektorientierung) mit dem offiziellen Lehrplan und Skriptum des Lehrers (**`rradlbauer/python_skriptum`**) ab.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Didaktische Leitlinien für die Nachhilfe
|
||||
|
||||
1. **Type Hints als Standard:** Da der Lehrer in Teil 2 strikt Typ-Annotationen verwendet (`name: str`, `def alter(self) -> int:`), führen wir diese ab den Klassen sauber ein.
|
||||
2. **UML-Klassendiagramme:** Das Skriptum fordert UML-Diagramme (`22.1_UML.md`). Jedes Kapitel enthält visuelle UML-Karten.
|
||||
3. **Echte Entwickler-Werkzeuge früh erlernen:** Nach den ersten OOP-Kapiteln folgen **VS Code (04b)** und **Git Versionskontrolle (04c)**, damit die Schülerin ab Kapitel 05 jedes gelöste Kapitel selbstständig versioniert und committet.
|
||||
4. **Eigene Unit Tests schreiben:** Ab Kapitel 09 lernt die Schülerin, wie man mit `unittest` eigene Testsuiten und Test-Driven Development (TDD) praktiziert.
|
||||
5. **Praxisnahe Analogien:** Statt trockener Theorie nutzen wir greifbare Alltagsbeispiele (Fahrrad-Verleih, Spotify-Playlists, Stammbäume, Geldautomaten).
|
||||
6. **Automatische Tests & Sofort-Feedback:** Jedes Kapitel hat ein Testskript (`test_aufgabe.py`), das bei `python3 test_aufgabe.py` oder `python3 test_all.py` sofort anzeigt, was schon klappt.
|
||||
7. **Autonomes Lernen:** Die Schülerin kann alle Kapitel über die modernen, interaktiven HTML-Seiten im Browser selbstständig durcharbeiten.
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Der Gesamtlehrplan im Überblick (Kapitel 00 bis 16)
|
||||
## 🧭 Die 3 Lehrpfade im Überblick
|
||||
|
||||
```
|
||||
PHASE 1: GRUNDLAGEN DER OBJEKTORIENTIERUNG (OOP) & TOOLING
|
||||
├── Kapitel 00: Fehlersuche & Python-Debugging (Warm-up)
|
||||
├── Kapitel 01: Erste Klasse & Baupläne (Lehrer 22.0 / 21.0 Type Hints)
|
||||
├── Kapitel 02: Konstruktor __init__, self & UML (Lehrer 22.0 / 22.1)
|
||||
├── Kapitel 03: Methoden & Objekt-Interaktion (Lehrer 22.0)
|
||||
├── Kapitel 04: Schöne Textausgabe mit __str__ (Lehrer 28.0)
|
||||
├── Kapitel 04b: Umstieg & Installation von VS Code (Lehrer 20.1)
|
||||
├── Kapitel 04c: Git & Versionskontrolle (VS Code & Terminal) 🌿
|
||||
├── Kapitel 05: Assoziation & Aggregation: Spotify Playlists (Lehrer 23.0)
|
||||
└── Kapitel 06: Mini-Abschlussprojekt: Tamagotchi Terminal-Game
|
||||
[ 🛣️ LEHRPFAD 1: GRUNDLAGEN DER PROGRAMMIERUNG (Prozedural & Datenstrukturen) ]
|
||||
├── G01: Python als Taschenrechner (Zahlen, Operatoren, Rangfolge) (Lehrer 02.1)
|
||||
├── G02: Variablen & Datentypen (int, float, str, bool, Type Casting) (Lehrer 03.0 & 03.1)
|
||||
├── G03: Interaktive Ein- & Ausgabe (input, print, formatierte f-Strings) (Lehrer 07.0)
|
||||
├── G04: Bedingungen & Verzweigungen (if, elif, else, and/or/not) (Lehrer 08.0)
|
||||
├── G05: Schleifen & Wiederholungen (for range, while, break, continue) (Lehrer 09.1 & 09.2)
|
||||
├── G06: Eigene Funktionen & Module (def, return, scope, math, random) (Lehrer 05.0 & 05.1)
|
||||
├── G07: Listen & Sequenzen (Indexing, Slicing, append/pop, sum/len/min) (Lehrer 09.0)
|
||||
├── G08: Textverarbeitung & Strings (.strip, .replace, .split, .join) (Lehrer 11.0)
|
||||
├── G09: Dictionaries & Sets ({key: value}, .get(), Mengen ohne Duplikate) (Lehrer 15.0)
|
||||
└── G10: Comprehensions, Datum & Algorithmen ([x for x in ...], datetime) (Lehrer 13.0 & 15.1)
|
||||
|
||||
PHASE 2: FORTGESCHRITTENES OOP, TESTING & SPEICHER
|
||||
├── Kapitel 07: Referenzen, Speicher & Stammbäume (Lehrer 24.0) 🧠
|
||||
├── Kapitel 08: Operator Overloading & Dunder-Methoden (Lehrer 28.0) ➕
|
||||
├── Kapitel 09: Eigene Unit Tests schreiben & TDD (unittest) 🧪
|
||||
├── Kapitel 10: Vererbung (Inheritance) & super() (Lehrer 25.0) 🧬
|
||||
├── Kapitel 11: Polymorphie & Duck Typing (Lehrer 25.1) 🎭
|
||||
├── Kapitel 12: Exceptions & Robuste Fehlerbehandlung (Lehrer 26.0) 🛡️
|
||||
└── Kapitel 13: Speichern & Laden: JSON & CSV Persistenz (Lehrer 14.0) 💾
|
||||
[ 🛣️ LEHRPFAD 2: EINSTIEG IN DIE OBJEKTORIENTIERUNG (OOP) & WERKZEUGE ]
|
||||
├── 00: Fehlersuche & Python-Debugging (Warm-up & Tracebacks) (Lehrer 04.1 & 07.1)
|
||||
├── 01: Erste Klasse & Baupläne (Instanziierung, Punktnotation) (Lehrer 22.0 & 21.0)
|
||||
├── 02: Konstruktor __init__, self & UML-Klassendiagramme (Lehrer 22.0 & 22.1)
|
||||
├── 03: Methoden & Objekt-Interaktionen (Rennauto & Duell) (Lehrer 22.0)
|
||||
├── 04: Schöne Textausgabe mit __str__ (Warenkorb & Bon) (Lehrer 28.0)
|
||||
├── 04b: Exkurs: Umstieg & Installation von VS Code (Lehrer 20.1)
|
||||
├── 04c: Exkurs: Git & Versionskontrolle (VS Code & Terminal) (Tooling)
|
||||
├── 05: Assoziation & Komposition (Spotify Playlist-Manager) (Lehrer 23.0)
|
||||
└── 06: Mini-Abschlussprojekt: Tamagotchi Terminal-Game (Konsolidierung)
|
||||
|
||||
PHASE 3: GRAFISCHE OBERFLÄCHEN & PROFESSIONS-MODULE
|
||||
├── Kapitel 14: Grafische Oberflächen mit Tkinter / CustomTkinter (Lehrer 27.0) 🖥️
|
||||
├── Kapitel 15: Erweiterte Parameter (*args, **kwargs) & Container (Lehrer 29/30) 📦
|
||||
└── Kapitel 16: Master-Abschlussprojekt: Grafische Desktop-App mit Savegame 🏆
|
||||
[ 🛣️ LEHRPFAD 3: FORTGESCHRITTENES OOP, SOFTWAREQUALITÄT & GUIS ]
|
||||
├── 07: Referenzen, RAM-Speicher & Familienstammbäume (Lehrer 24.0)
|
||||
├── 08: Operator Overloading & Dunder-Methoden (__add__, __eq__, __lt__) (Lehrer 28.0)
|
||||
├── 09: Eigene Unit Tests schreiben & TDD (unittest.TestCase) (Testing & TDD)
|
||||
├── 10: Vererbung (Inheritance) & super() (Fahrzeugflotte) (Lehrer 25.0)
|
||||
├── 11: Polymorphie & Interfaces (ABC, Geometrie & Zeichenfläche) (Lehrer 25.1)
|
||||
├── 12: Exceptions & Robuste Fehlerbehandlung (try-except, Bankkonto) (Lehrer 26.0)
|
||||
├── 13: Datei-Persistenz: JSON & CSV Speichern (Savegames) (Lehrer 14.0)
|
||||
└── 14: Desktop-GUIs mit Tkinter & MVC-Architektur (Zähler & Rechner) (Lehrer 27.0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📑 Detaillierte Kapitel-Übersicht & Abgleich
|
||||
## 📑 Detaillierte Themen-Abgleichstabelle
|
||||
|
||||
| Kapitel | Titel / Thema | Lehrerskript-Referenz | Kerninhalte & Praxisaufgabe |
|
||||
| Modul | Titel | Thema | Praxisbeispiel |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **00** | **Fehlersuche & Debugging** | *04.1 & 07.1* | Tracebacks von unten lesen, `IndentationError`, `SyntaxError`, `TypeError`, Detektiv-Aufgabe |
|
||||
| **01** | **Einstieg in Klassen** | *22.0 & 21.0* | Bauplan vs. Objekt, Instanziierung, Punktnotation, erste Type Hints (`Fahrrad`) |
|
||||
| **02** | **Konstruktor & self** | *22.0 & 22.1* | `__init__`, `self`, Startwerte, erstes UML-Klassendiagramm (`Bankkonto` & `Smartphone`) |
|
||||
| **03** | **Methoden & Verhalten** | *22.0* | Methoden definieren, Rückgabewerte, Interaktion zweier Objekte (`Rennauto` & RPG-Duell) |
|
||||
| **04** | **`__str__` & Darstellung** | *28.0* | Dunder-Methode `__str__`, lesbare Ausgabe von Objekten, Kassenzettel (`Warenkorb`) |
|
||||
| **04b** | **VS Code Umstieg** | *20.1* | Installation (Windows/Mac/Linux), Plugins (Error Lens, Python), Shortcuts, Projektordner |
|
||||
| **04c** | **Git Versionskontrolle** | *Tooling* | Was ist Git? Spielstand-Analogie, `git add`, `git commit`, `git push`, VS Code Git-Tab |
|
||||
| **05** | **Objekte kombinieren** | *23.0* | Assoziation & Aggregation (1:1 und 1:n), Listen von Objekten filtern (`Spotify Playlist`) |
|
||||
| **06** | **Abschlussprojekt OOP 1** | *Konsolidierung* | Tamagotchi-Konsolenspiel (Lebenszyklus, Hunger, Müdigkeit, Zufallsevents) |
|
||||
| **07** | **Referenzen & Speicher** | *24.0 Referenzen* | RAM-Visualisierung, Mutable vs. Immutable, `is` vs. `==`, Aliasing, `Stammbaum`-Projekt |
|
||||
| **08** | **Operator Overloading** | *28.0 Spezielle Methoden*| `__add__`, `__sub__`, `__eq__`, `__lt__`, `__len__` (2D-Vektoren & Kartenspiel) |
|
||||
| **09** | **Eigene Unit Tests & TDD**| *Softwarequalität* | Testsuiten schreiben mit `unittest`, `assertEqual`, `assertTrue`, `assertRaises` |
|
||||
| **10** | **Vererbung & `super()`** | *25.0 Vererbung* | Basisklassen, Kindklassen, Vermeidung von Code-Duplikaten, `super().__init__()` (`Fahrzeuge`) |
|
||||
| **11** | **Polymorphie & Interfaces**| *25.1 Polymorphie* | Methoden überschreiben, gemeinsames Interface, Geometrie- & Grafik-Engine (`Formen`) |
|
||||
| **12** | **Exceptions & Fehler** | *26.0 Exceptions* | `try/except/else/finally`, `raise`, eigene Exception-Klassen (`Geldautomat`) |
|
||||
| **13** | **JSON & CSV Speichern** | *14.0 CSV / Persistenz* | `with open()`, `json.dump`/`json.load`, Spielstände dauerhaft sichern (`Savegame`) |
|
||||
| **14** | **Tkinter Desktop-GUI** | *27.0 Tkinter* | Fenster, Buttons, Labels, Eingabefelder, Event-Handling in OOP-Klassen |
|
||||
| **15** | **Parameter & Container** | *29.0 & 30.0 Parameter*| `*args`, `**kwargs`, Dunder `__getitem__`, `__iter__` für eigene Listen-Container |
|
||||
| **16** | **Master-Abschlussprojekt**| *Meisterstück* | Vollständige Desktop-App mit grafischer Oberfläche, Speichern & Laden |
|
||||
| **G01** | **Taschenrechner** | Grundrechenarten, `//`, `%`, `**`, Rangfolge | Rechner-Funktionen & Kreisflächen |
|
||||
| **G02** | **Variablen & Typen** | Basisdatentypen, Type Casting, Type Hints | Typen-Erkenner & Preis-Formatierer |
|
||||
| **G03** | **Ein- & Ausgabe** | `input()`, f-Strings mit Formatierungs-Codes | Steckbrief & Rechnungsposten |
|
||||
| **G04** | **Verzweigungen** | `if`, `elif`, `else`, `and`, `or`, `not` | Kinokarten, Notenspiegel & Schaltjahr |
|
||||
| **G05** | **Schleifen** | `for in range()`, `while`, `break`, `continue` | Fakultät, Primzahlen & Quersummen |
|
||||
| **G06** | **Funktionen** | `def`, `return`, Scope, `math`, `random` | Hypotenuse, Zylindervolumen & Würfel |
|
||||
| **G07** | **Listen & Slicing**| Indexing, Slicing `[1:4]`, Methoden wie `append`/`pop` | Notenschnitt ohne Ausreißer |
|
||||
| **G08** | **Textverarbeitung**| String-Methoden (`.strip`, `.split`, `.replace`) | Palindrom-Prüfer & Kreditkarten-Maske |
|
||||
| **G09** | **Dicts & Sets** | Key-Value Paare, `.get()`, Mengen ohne Duplikate | Häufigkeitszähler & Hobbys-Abgleich |
|
||||
| **G10** | **Comprehensions** | `[x for x in ...]`, `datetime`, Sortier-Algorithmen | Countdown, Alters-Suche |
|
||||
| **00** | **Fehlersuche** | Tracebacks von unten lesen, `IndentationError` | Code-Detektivin |
|
||||
| **01** | **Erste Klasse** | Klassen als Baupläne, Punktnotation, Type Hints | Fahrrad-Verleih |
|
||||
| **02** | **Konstruktor** | `__init__`, `self`, Startwerte, UML-Diagramme | Bankkonto & Smartphone |
|
||||
| **03** | **Methoden** | Verhalten & Interaktion zweier Objekte | Rennauto-Duell |
|
||||
| **04** | **`__str__`** | Lesbare Darstellung mit `print()`, Rechnungsdruck | Pizzeria-Warenkorb |
|
||||
| **04b** | **VS Code** | Installation, Extensions (Error Lens, Python), Shortcuts | IDE-Praxis |
|
||||
| **04c** | **Git** | Spielstand-Analogie, Commits, VS Code Git-Tab, Push | Versionskontrolle |
|
||||
| **05** | **Komposition** | 1:1 und 1:n Beziehungen zwischen Objekten | Spotify Playlist-Manager |
|
||||
| **06** | **Mini-Projekt**| Konsolidierung von OOP Teil 1 | Tamagotchi Konsolenspiel |
|
||||
| **07** | **Referenzen** | RAM-Zeiger, Aliasing (`b = a`), `is` vs. `==` | Familienstammbaum (`Person`) |
|
||||
| **08** | **Dunder** | Operator Overloading `__add__`, `__eq__`, `__len__` | 2D-Vektor & Wegstrecken |
|
||||
| **09** | **Unit Testing**| Eigene Testsuiten schreiben, `assertEqual`, TDD | Taschenrechner & Bankkonto Tests |
|
||||
| **10** | **Vererbung** | Basis- und Kindklassen, `super().__init__()`, DRY | Fahrzeugflotte (`ElektroAuto`, `Lkw`) |
|
||||
| **11** | **Polymorphie** | Duck Typing, abstrakte Klassen (`ABC`), Overriding | Geometrie-Engine & Zeichenfläche |
|
||||
| **12** | **Exceptions** | `try-except-else-finally`, `raise`, eigene Fehler | Bankkonto- & Geldautomat-Simulator |
|
||||
| **13** | **Persistenz** | `with open()`, `json.dump`/`load`, CSV-Export | Savegames & Notenbuch |
|
||||
| **14** | **Tkinter GUI** | Echte Desktop-Apps, Widgets, `grid()`, MVC-Muster | Interaktive Zähler- & Rechner-App |
|
||||
|
|
|
|||
82
README.md
82
README.md
|
|
@ -1,39 +1,55 @@
|
|||
# 🐍 Python OOP Übungsreihe: Der Einstieg in Klassen & Objekte
|
||||
# 🐍 Python Lernportal: Vom Einsteiger zum Software-Entwickler
|
||||
|
||||
Willkommen zu deiner Übungsreihe für **Objektorientierte Programmierung (OOP)** in Python! 🎉
|
||||
Willkommen zum interaktiven **Python Lernportal**! 🎉
|
||||
|
||||
Diese Übungsreihe ist didaktisch aufbereitet und **1:1 mit dem offiziellen Lehrplan des Informatik-Unterrichts** ([`LEHRPLAN.md`](./LEHRPLAN.md)) abgeglichen.
|
||||
Dieses Portal ist didaktisch aufbereitet, voll **abgeglichen mit dem Informatik-Schulunterricht** ([`LEHRPLAN.md`](./LEHRPLAN.md)) und gliedert sich in **3 strukturierte Lehrpfade**:
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Der Lernpfad
|
||||
## 🧭 Die 3 Lehrpfade
|
||||
|
||||
### 🌱 Phase 1: Grundlagen OOP & Werkzeuge
|
||||
| Kapitel | Thema | Was du lernst |
|
||||
### 🛣️ Lehrpfad 1: Grundlagen der Programmierung (Prozedural & Datenstrukturen)
|
||||
| Modul | Titel | Themenschwerpunkte |
|
||||
| :--- | :--- | :--- |
|
||||
| **[00. Fehlersuche & Grundlagen](./00_fehlersuche_und_grundlagen/)** | Warm-up & Debugging | Tracebacks lesen, Einrückungen (`IndentationError`), Typfehler & Detektiv-Aufgabe |
|
||||
| **[01. Einstieg in Klassen](./01_einstieg_klassen/)** | Warum Klassen? | Bauplan vs. Objekt, Instanziierung, Punktnotation & Type Hints |
|
||||
| **[02. Konstruktor & self](./02_init_und_self/)** | `__init__`, `self` & UML | Objekte sauber initialisieren und erste UML-Klassendiagramme |
|
||||
| **[03. Methoden & Verhalten](./03_methoden_und_verhalten/)** | Methoden & Interaktion | Objekte können handeln & miteinander im Duell interagieren |
|
||||
| **[04. Schöne Textausgabe](./04_str_und_darstellung/)** | `__str__` Dunder-Methode | Wie Objekte lesbar mit `print()` ausgegeben werden (Warenkorb & Bon) |
|
||||
| **[04b. Umstieg & Installation VS Code](./04b_umstieg_vscode/)** | **Exkurs: IDE-Wechsel** | **Installation (Win/Mac/Linux), Plugins (Error Lens, Python), Shortcuts & Terminal** |
|
||||
| **[04c. Git & Versionskontrolle](./04c_git_und_versionskontrolle/)** | **Exkurs: Git-Tooling** | **Spielstände (Commits) sichern, VS Code Git-Tab, Terminal-Befehle & Remote Push** |
|
||||
| **[05. Objekte kombinieren](./05_objekte_kombinieren/)** | Assoziation & Komposition | Listen von Objekten & Spotify-Playlists filtern und berechnen |
|
||||
| **[06. Abschlussprojekt OOP 1](./06_abschlussprojekt_tamagotchi/)** | Mini-Projekt: Tamagotchi | Ein interaktives Konsolenspiel mit allem Gelernten |
|
||||
| **[G01. Taschenrechner](./g01_erste_schritte_taschenrechner/)** | **Python als Rechner** | Zahlenarten (`int`, `float`), Grundrechenarten, `//`, `%`, `**`, Rangfolge & `print()` |
|
||||
| **[G02. Variablen & Typen](./g02_variablen_und_datentypen/)** | **Datentypen** | Speicherboxen, `int`, `float`, `str`, `bool`, Type Casting & Type Hints |
|
||||
| **[G03. Ein- & Ausgabe](./g03_ein_und_ausgabe/)** | **Interaktion** | Tastatureingaben mit `input()`, f-Strings mit Formatierungs-Codes (`{preis:.2f} €`) |
|
||||
| **[G04. Bedingungen](./g04_verzweigungen_und_bedingungen/)** | **Entscheidungen** | `if`, `elif`, `else`, Vergleichsoperatoren & Logik (`and`, `or`, `not`) |
|
||||
| **[G05. Schleifen](./g05_schleifen_und_wiederholungen/)** | **Wiederholungen** | Zählschleifen mit `for in range()`, Bedingungsschleifen mit `while`, `break`/`continue` |
|
||||
| **[G06. Funktionen](./g06_funktionen_und_module/)** | **Modularität** | `def`, `return`, Parameter, Scope & Module (`math`, `random`) |
|
||||
| **[G07. Listen & Sequenzen](./g07_listen_und_sequenzen/)** | **Datenstrukturen 1** | Listen erstellen, Indexing, Slicing `[1:4]`, Methoden (`append`, `pop`) & `sum/min/max` |
|
||||
| **[G08. Textverarbeitung](./g08_textverarbeitung_und_strings/)** | **String-Methoden** | Unveränderlichkeit, `.strip()`, `.replace()`, `.split()`, `", ".join()` & Textanalyse |
|
||||
| **[G09. Dictionaries & Sets](./g09_dictionaries_und_sets/)** | **Datenstrukturen 2** | Key-Value Paare (`{key: val}`), sicheres `.get()`, Mengen (`set`) ohne Duplikate |
|
||||
| **[G10. Comprehensions & Datum](./g10_comprehensions_datum_algorithmen/)** | **Vertiefung** | List Comprehensions `[x for x in ...]`, `datetime` & Such-/Sortier-Algorithmen |
|
||||
|
||||
### 🧠 Phase 2: Fortgeschrittenes OOP, Testing & Persistenz
|
||||
| Kapitel | Thema | Was du lernst |
|
||||
---
|
||||
|
||||
### 🛣️ Lehrpfad 2: Einstieg in die Objektorientierung (OOP) & Entwickler-Tools
|
||||
| Modul | Titel | Themenschwerpunkte |
|
||||
| :--- | :--- | :--- |
|
||||
| **[07. Referenzen, Speicher & Stammbäume](./07_referenzen_und_speicher/)** | **Speicher & RAM** | **Referenzen, Aliasing (`b = a`), Mutable vs. Immutable, `is` vs. `==` & Familienstammbaum** |
|
||||
| **[08. Operator Overloading](./08_operator_overloading_dunder/)** | **Dunder-Methoden** | **`__add__`, `__mul__`, `__eq__`, `__lt__` (2D-Vektoren & Wegstrecken)** |
|
||||
| **[09. Eigene Unit Tests & TDD](./09_eigene_unit_tests_schreiben/)** | **Softwarequalität** | **Testsuiten schreiben mit `unittest`, `assertEqual`, `assertTrue`, `assertRaises`** |
|
||||
| **[10. Vererbung & `super()`](./10_vererbung_und_super/)** | **Inheritance** | **Basisklassen, Kindklassen, DRY-Prinzip & `super().__init__()` (Fahrzeugflotte)** |
|
||||
| **[11. Polymorphie & Interfaces](./11_polymorphie_und_interfaces/)** | **Polymorphism** | **Vielgestaltigkeit, Duck Typing, abstrakte Basisklassen (`ABC`) & Geometrie-Engine** |
|
||||
| **[12. Exceptions & Fehler](./12_exceptions_und_fehlerbehandlung/)** | **Robustes Coding** | **`try/except/else/finally`, `raise`, eigene Exception-Klassen (Bankkonto)** |
|
||||
| **[13. JSON & CSV Speichern](./13_persistenz_json_und_csv/)** | **Persistenz** | **Spielstände dauerhaft mit JSON/CSV auf der Festplatte sichern** |
|
||||
| **[14. Desktop-GUIs mit Tkinter](./14_gui_mit_tkinter/)** | **Grafische Oberflächen** | **Fenster, Buttons, Labels, Grid-Layout & MVC-Architektur** |
|
||||
| **[00. Fehlersuche](./00_fehlersuche_und_grundlagen/)** | **Warm-up & Debugging** | Tracebacks von unten lesen, `IndentationError`, `SyntaxError`, `TypeError` |
|
||||
| **[01. Einstieg in Klassen](./01_einstieg_klassen/)** | **Bauplan vs. Objekt** | Klassen definieren, Instanziierung, Punktnotation & Type Hints (`Fahrrad`) |
|
||||
| **[02. Konstruktor & self](./02_init_und_self/)** | **Initialisierung & UML** | `__init__`, `self`, Startwerte & UML-Klassendiagramme (`Bankkonto`, `Smartphone`) |
|
||||
| **[03. Methoden & Verhalten](./03_methoden_und_verhalten/)** | **Objekt-Interaktion** | Methoden definieren, Rückgabewerte & Duell zweier Objekte (`Rennauto`) |
|
||||
| **[04. Schöne Textausgabe](./04_str_und_darstellung/)** | **`__str__` Dunder** | Lesbare `print()`-Ausgabe von Objekten, Kassenzettel (`Warenkorb`) |
|
||||
| **[04b. VS Code Installation](./04b_umstieg_vscode/)** | **IDE-Setup** | Installation (Win/Mac/Linux), Plugins (Error Lens, Python), Shortcuts |
|
||||
| **[04c. Git & Versionskontrolle](./04c_git_und_versionskontrolle/)** | **Git-Tooling** | Spielstände (Commits) sichern, VS Code Git-Tab, Terminal & Remote Push |
|
||||
| **[05. Objekte kombinieren](./05_objekte_kombinieren/)** | **Komposition** | 1:1 und 1:n Beziehungen zwischen Objekten (`Spotify Playlist-Manager`) |
|
||||
| **[06. Mini-Projekt OOP 1](./06_abschlussprojekt_tamagotchi/)** | **Tamagotchi Game** | Voll spielbares, interaktives Haustierspiel im Terminal |
|
||||
|
||||
*(Den vollständigen didaktischen Masterplan für alle Kapitel bis 16 findest du in [`LEHRPLAN.md`](./LEHRPLAN.md).)*
|
||||
---
|
||||
|
||||
### 🛣️ Lehrpfad 3: Fortgeschrittenes OOP, Softwarequalität & Desktop-GUIs
|
||||
| Modul | Titel | Themenschwerpunkte |
|
||||
| :--- | :--- | :--- |
|
||||
| **[07. Referenzen & Speicher](./07_referenzen_und_speicher/)** | **RAM & Zeiger** | Referenzen im RAM, Aliasing (`b = a`), `is` vs. `==` & Familienstammbaum (`Person`) |
|
||||
| **[08. Operator Overloading](./08_operator_overloading_dunder/)** | **Dunder-Methoden** | Eigene Klassen rechenbar machen mit `__add__`, `__mul__`, `__eq__` (2D-Vektoren) |
|
||||
| **[09. Eigene Unit Tests & TDD](./09_eigene_unit_tests_schreiben/)** | **Softwarequalität** | Testsuiten schreiben mit `unittest`, `assertEqual`, `assertRaises` & TDD |
|
||||
| **[10. Vererbung & `super()`](./10_vererbung_und_super/)** | **Inheritance** | Basis- & Kindklassen, DRY-Prinzip, `super().__init__()` & Fahrzeugflotte |
|
||||
| **[11. Polymorphie & Interfaces](./11_polymorphie_und_interfaces/)** | **Polymorphism** | Duck Typing, abstrakte Basisklassen (`ABC`) & Geometrie-Engine |
|
||||
| **[12. Exceptions & Fehler](./12_exceptions_und_fehlerbehandlung/)** | **Robustes Coding** | `try-except-else-finally`, `raise`, eigene Exception-Klassen im Banking |
|
||||
| **[13. Datei-Persistenz](./13_persistenz_json_und_csv/)** | **JSON & CSV** | Dauerhaftes Speichern & Laden: Savegames & Tabellen-Export |
|
||||
| **[14. Desktop-GUIs mit Tkinter](./14_gui_mit_tkinter/)** | **Tkinter Desktop-Apps** | Echte Fenster, Buttons, Labels, Grid-Layout & MVC-Architektur |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -44,17 +60,17 @@ In jedem Kapitelordner liegt eine Datei namens `test_aufgabe.py`. Sie enthält a
|
|||
### 1. Einzelnes Kapitel testen
|
||||
Öffne das Terminal in VS Code (`Strg + \``) und führe den Test im jeweiligen Ordner aus:
|
||||
```bash
|
||||
# Beispiel für Kapitel 01:
|
||||
cd 01_einstieg_klassen
|
||||
# Beispiel für Grundlagen G01:
|
||||
cd g01_erste_schritte_taschenrechner
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
|
||||
### 2. Testausgabe richtig lesen:
|
||||
- ✅ **`OK`**: Perfekt! Alle Tests sind grün und bestanden. Du kannst mit dem nächsten Kapitel weitermachen.
|
||||
- ❌ **`FAIL` (AssertionError)**: Dein Code läuft, liefert aber einen falschen Wert zurück (z.B. Rechenfehler oder falsche Bedingung). Lies die letzte Zeile der Fehlermeldung!
|
||||
- 💥 **`ERROR` (Syntax / AttributeError)**: Dein Code hat einen Absturz (z.B. Tippfehler im Methodennamen oder `self` im Methodenkopf vergessen).
|
||||
- 💥 **`ERROR` (Syntax / AttributeError)**: Dein Code hat einen Absturz (z.B. Tippfehler im Funktionsnamen).
|
||||
|
||||
### 3. Gesamten Fortschritt aller Kapitel prüfen:
|
||||
### 3. Gesamten Fortschritt aller 25 Kapitel prüfen:
|
||||
Führe im Hauptordner folgenden Befehl aus:
|
||||
```bash
|
||||
python3 test_all.py
|
||||
|
|
@ -65,6 +81,6 @@ Dieser Befehl zeigt dir eine Übersicht über alle Kapitel mit `✅` (bestanden)
|
|||
|
||||
## 💡 3 Wichtige Regeln für die Aufgaben
|
||||
|
||||
1. **`return` statt `print()`:** Tests prüfen das, was eine Methode mit `return` zurückliefert. Ein reines `print()` genügt dem Test nicht!
|
||||
2. **Exakte Namen:** Die Namen der Methoden und Attribute müssen exakt der Aufgabenstellung entsprechen (`mutter_setzen`, nicht `MutterSetzen`).
|
||||
3. **Immer `self` als erster Methoden-Parameter:** Jede Methode in einer Klasse muss `def meine_methode(self, ...):` geschrieben werden.
|
||||
1. **`return` statt `print()`:** Tests prüfen das, was eine Funktion/Methode mit `return` zurückliefert. Ein reines `print()` genügt dem Test nicht!
|
||||
2. **Exakte Namen:** Die Namen der Funktionen, Methoden und Attribute müssen exakt der Aufgabenstellung entsprechen (`addieren`, nicht `Addieren`).
|
||||
3. **Fehlermeldungen von unten nach oben lesen:** Ganz unten im Traceback steht immer die genaue Ursache.
|
||||
|
|
|
|||
92
g01_erste_schritte_taschenrechner/README.md
Normal file
92
g01_erste_schritte_taschenrechner/README.md
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# Grundlagen 01: Python als Taschenrechner 🧮 (Schulabgleich 02.1)
|
||||
|
||||
Willkommen zum ersten Kapitel des Python-Grundlagen-Lehrpfads!
|
||||
|
||||
In diesem Kapitel lernst du, wie Python als extrem präziser und vielseitiger Taschenrechner verwendet wird, welche Zahlenarten es gibt und wie die mathematischen Operatoren funktionieren.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Das Wichtigste in Kürze
|
||||
|
||||
### 1. Zahlenarten in Python
|
||||
Python unterscheidet grundlegend zwischen zwei Zahlenarten:
|
||||
- **`int` (Integer):** Ganze Zahlen ohne Nachkommastellen (z.B. `42`, `-5`, `0`, `1000000`). Python kann mit beliebig großen ganzen Zahlen rechnen!
|
||||
- **`float` (Floating Point Number):** Kommazahlen mit Nachkommastellen (z.B. `3.14`, `-0.5`, `2.0`). Beachte: In Python wird als Dezimaltrennzeichen immer ein **Punkt `.`** verwendet, kein Komma!
|
||||
|
||||
---
|
||||
|
||||
## 🧮 Die 7 Rechenoperatoren in Python
|
||||
|
||||
| Operator | Name | Beispiel | Ergebnis | Besonderheit / Erklärung |
|
||||
| :---: | :--- | :--- | :---: | :--- |
|
||||
| `+` | Addition | `12 + 8` | `20` | Addiert zwei Zahlen |
|
||||
| `-` | Subtraktion | `20 - 7` | `13` | Subtrahiert den zweiten Wert vom ersten |
|
||||
| `*` | Multiplikation | `6 * 7` | `42` | Multipliziert zwei Zahlen |
|
||||
| `/` | Echte Division | `7 / 2` | `3.5` | **Wichtig:** Liefert in Python 3 *immer* ein `float` (Kommazahl)! `4 / 2` ergibt `2.0`. |
|
||||
| `//` | Ganzzahldivision | `17 // 5` | `3` | Teilt und rundet immer zur nächsten ganzen Zahl nach unten ab (Floor Division). |
|
||||
| `%` | Modulo | `17 % 5` | `2` | Berechnet den verbleibenden **Rest** einer Ganzzahldivision. |
|
||||
| `**` | Potenz | `2 ** 3` | `8` | Berechnet $2^3 = 2 \times 2 \times 2 = 8$. |
|
||||
|
||||
---
|
||||
|
||||
## 🍕 Pizza-Analogie für `//` und `%`
|
||||
|
||||
Stell dir vor, du bestellst eine Pizza mit **17 Stücken** für **5 Personen**:
|
||||
- Wie viele ganze Stücke bekommt jede Person fair aufgeteilt?
|
||||
$$\text{Stücke pro Person} = 17 // 5 = 3$$
|
||||
- Wie viele Stücke bleiben in der Schachtel übrig?
|
||||
$$\text{Rest} = 17 \% 5 = 2$$
|
||||
- Probe: $3 \times 5 + 2 = 17$!
|
||||
|
||||
---
|
||||
|
||||
## 📐 Vorrangregeln (Punkt vor Strich & Klammern)
|
||||
|
||||
Genau wie in der Schulmathematik beachtet Python feste Vorrangregeln:
|
||||
1. **Klammern `(...)`** haben immer die höchste Priorität.
|
||||
2. **Potenzen `**`** werden vor Multiplikation/Division berechnet.
|
||||
3. **Punktrechnung `*`, `/`, `//`, `%`** kommt vor **Strichrechnung `+`, `-`**.
|
||||
|
||||
```python
|
||||
# Ohne Klammer: 3 * 4 = 12, dann 2 + 12 = 14
|
||||
ergebnis = 2 + 3 * 4 # 14
|
||||
|
||||
# Mit Klammer: (2 + 3) = 5, dann 5 * 4 = 20
|
||||
ergebnis = (2 + 3) * 4 # 20
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📢 Textausgabe mit `print()`
|
||||
|
||||
Mit der eingebauten Funktion `print()` gibst du Texte und Rechenergebnisse im Terminal aus:
|
||||
|
||||
```python
|
||||
print("Hallo Welt!")
|
||||
print("Ergebnis:", 40 + 2)
|
||||
print(f"Die Kreisfläche beträgt: {3.14159 * 5**2}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne die Datei `aufgabe.py` und bearbeite die folgenden 7 TODOs:
|
||||
1. **TODO 1:** `addieren(a, b)` $\rightarrow$ Summe $a + b$
|
||||
2. **TODO 2:** `subtrahieren(a, b)` $\rightarrow$ Differenz $a - b$
|
||||
3. **TODO 3:** `multiplizieren(a, b)` $\rightarrow$ Produkt $a \times b$
|
||||
4. **TODO 4:** `dividieren(a, b)` $\rightarrow$ Quotient $a / b$ (als float)
|
||||
5. **TODO 5:** `ganzzahl_rest(a, b)` $\rightarrow$ Tupel `(a // b, a % b)`
|
||||
6. **TODO 6:** `potenz(basis, exponent)` $\rightarrow$ $basis^{exponent}$ (`basis ** exponent`)
|
||||
7. **TODO 7:** `kreis_flaeche(radius)` $\rightarrow$ $3.14159 \times radius^2$
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Lösung überprüfen
|
||||
|
||||
Führe im Terminal den automatischen Unittest aus:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
|
||||
Wenn alle 7 Tests mit `OK` durchlaufen, bist du bereit für das nächste Kapitel: **G02: Variablen & Datentypen**!
|
||||
144
g01_erste_schritte_taschenrechner/aufgabe.py
Normal file
144
g01_erste_schritte_taschenrechner/aufgabe.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
"""
|
||||
Grundlagen 01: Python als Taschenrechner – Aufgabenblatt
|
||||
=========================================================
|
||||
|
||||
In diesem Kapitel lernst du, wie Python als leistungsfähiger Taschenrechner
|
||||
funktioniert und wie du mathematische Operationen in Funktionen kapselst.
|
||||
|
||||
Bearbeite die Aufgaben Schritt für Schritt von TODO 1 bis TODO 7.
|
||||
Wenn du fertig bist, überprüfe deine Lösung im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Schreibe die Funktion 'addieren(a, b)'
|
||||
#
|
||||
# Die Funktion soll zwei Zahlen (int oder float) entgegennehmen und deren
|
||||
# mathematische Summe (a + b) zurückgeben.
|
||||
#
|
||||
# Beispiel:
|
||||
# addieren(5, 3) -> 8
|
||||
# addieren(2.5, 1.5) -> 4.0
|
||||
# ==============================================================================
|
||||
|
||||
def addieren(a: float, b: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schreibe die Funktion 'subtrahieren(a, b)'
|
||||
#
|
||||
# Die Funktion soll die Differenz von a und b (a - b) berechnen und zurückgeben.
|
||||
#
|
||||
# Beispiel:
|
||||
# subtrahieren(10, 4) -> 6
|
||||
# subtrahieren(3, 5) -> -2
|
||||
# ==============================================================================
|
||||
|
||||
def subtrahieren(a: float, b: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schreibe die Funktion 'multiplizieren(a, b)'
|
||||
#
|
||||
# Die Funktion soll das Produkt von a und b (a * b) berechnen und zurückgeben.
|
||||
#
|
||||
# Beispiel:
|
||||
# multiplizieren(6, 7) -> 42
|
||||
# multiplizieren(4, 0.5) -> 2.0
|
||||
# ==============================================================================
|
||||
|
||||
def multiplizieren(a: float, b: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Schreibe die Funktion 'dividieren(a, b)'
|
||||
#
|
||||
# Die Funktion soll den Quotienten von a und b (a / b) berechnen und zurückgeben.
|
||||
# Hinweis: Die Division '/' in Python liefert immer eine Kommazahl (float).
|
||||
#
|
||||
# Beispiel:
|
||||
# dividieren(10, 2) -> 5.0
|
||||
# dividieren(7, 2) -> 3.5
|
||||
# ==============================================================================
|
||||
|
||||
def dividieren(a: float, b: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 5: Schreibe die Funktion 'ganzzahl_rest(a, b)'
|
||||
#
|
||||
# Die Funktion soll zwei ganze Zahlen a und b annehmen und ein Tupel mit zwei
|
||||
# Werten zurückgeben: (quotient, rest)
|
||||
# 1. Der ganzzahlige Quotient (mit Ganzzahldivision '//')
|
||||
# 2. Der verbleibende Rest (mit Modulo-Operator '%')
|
||||
#
|
||||
# Beispiel:
|
||||
# ganzzahl_rest(17, 5) -> (3, 2) # 17 // 5 ist 3, Rest 17 % 5 ist 2
|
||||
# ganzzahl_rest(20, 4) -> (5, 0) # 20 // 4 ist 5, Rest 20 % 4 ist 0
|
||||
# ==============================================================================
|
||||
|
||||
def ganzzahl_rest(a: int, b: int) -> tuple:
|
||||
# Schreibe hier deinen Code für TODO 5:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 6: Schreibe die Funktion 'potenz(basis, exponent)'
|
||||
#
|
||||
# Die Funktion soll 'basis' hoch 'exponent' berechnen (mit dem Operator '**').
|
||||
#
|
||||
# Beispiel:
|
||||
# potenz(2, 3) -> 8 # 2 * 2 * 2 = 8
|
||||
# potenz(5, 2) -> 25 # 5 * 5 = 25
|
||||
# potenz(10, 0) -> 1
|
||||
# ==============================================================================
|
||||
|
||||
def potenz(basis: float, exponent: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 6:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 7: Schreibe die Funktion 'kreis_flaeche(radius)'
|
||||
#
|
||||
# Berechne die Fläche eines Kreises mit der Formel:
|
||||
# flaeche = pi * r^2
|
||||
# Verwende für Pi den Näherungswert 3.14159.
|
||||
# Rechne: 3.14159 * (radius ** 2)
|
||||
#
|
||||
# Beispiel:
|
||||
# kreis_flaeche(1) -> 3.14159
|
||||
# kreis_flaeche(2) -> 12.56636 # (3.14159 * 4)
|
||||
# ==============================================================================
|
||||
|
||||
def kreis_flaeche(radius: float) -> float:
|
||||
# Schreibe hier deinen Code für TODO 7:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Führe diese Datei direkt aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 50)
|
||||
print("🧮 PYTHON ALS TASCHENRECHNER – TEST-AUSGABE")
|
||||
print("=" * 50)
|
||||
|
||||
print("Addition (12 + 8):", addieren(12, 8))
|
||||
print("Subtraktion (20 - 7):", subtrahieren(20, 7))
|
||||
print("Multiplikation (6 * 7):", multiplizieren(6, 7))
|
||||
print("Division (15 / 2):", dividieren(15, 2))
|
||||
print("Ganzzahl & Rest (17 durch 5):", ganzzahl_rest(17, 5))
|
||||
print("Potenz (2 hoch 8):", potenz(2, 8))
|
||||
print("Kreisfläche (Radius 5):", kreis_flaeche(5))
|
||||
|
||||
print("\n💡 Führe 'python3 test_aufgabe.py' aus, um deine Lösungen zu prüfen!")
|
||||
305
g01_erste_schritte_taschenrechner/index.html
Normal file
305
g01_erste_schritte_taschenrechner/index.html
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Grundlagen 01: Python als Taschenrechner</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Grundlagen 01</span>
|
||||
<span>›</span>
|
||||
<a href="../g02_variablen_und_datentypen/index.html">Grundlagen 02 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen 01 • Schulabgleich 02.1</div>
|
||||
<h1>Python als Taschenrechner 🧮</h1>
|
||||
<p>Lerne die Grundrechenarten, besondere Operatoren wie Modulo und Ganzzahldivision sowie Punkt-vor-Strich-Regeln in Python kennen.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie: Python als Super-Taschenrechner -->
|
||||
<section class="card">
|
||||
<h2>1. Die Taschenrechner-Analogie 💡</h2>
|
||||
<p>
|
||||
Bevor wir riesige Programme und Klassen bauen, starten wir mit der einfachsten Eigenschaft von Python: <strong>Python ist der schnellste und präziseste Taschenrechner der Welt!</strong>
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🧠 Warum ist Python besser als ein gewöhnlicher Taschenrechner?</div>
|
||||
Ein normaler Taschenrechner hat oft ein Limit bei 10 oder 12 Stellen. Python hingegen rechnet mit beliebig großen Zahlen (sogar Zahlen mit hunderten Ziffern!) und verarbeitet komplexe mathematische Formeln fehlerfrei nach den universellen Rechengesetzen.
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Python Interaktiv (REPL / Terminal)</span>
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
</div>
|
||||
<pre><span class="cm"># Einfach eintippen – Python rechnet sofort:</span>
|
||||
>>> <span class="num">12</span> + <span class="num">8</span>
|
||||
<span class="num">20</span>
|
||||
|
||||
>>> <span class="num">100</span> * <span class="num">5</span>
|
||||
<span class="num">500</span>
|
||||
|
||||
>>> <span class="num">2</span> ** <span class="num">10</span> <span class="cm"># 2 hoch 10</span>
|
||||
<span class="num">1024</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Zahlenarten: int vs. float -->
|
||||
<section class="card">
|
||||
<h2>2. Ganze Zahlen (<code>int</code>) vs. Kommazahlen (<code>float</code>)</h2>
|
||||
<p>
|
||||
In Python gibt es zwei fundamentale Typen von Zahlen:
|
||||
</p>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">🔢 Die zwei Zahlenwelten:</div>
|
||||
<ul style="margin-left: 20px; margin-top: 6px;">
|
||||
<li><strong><code>int</code> (Integer):</strong> Ganze Zahlen ohne Nachkommastellen (z.B. <code>42</code>, <code>-7</code>, <code>0</code>, <code>1000000</code>).</li>
|
||||
<li><strong><code>float</code> (Floating Point):</strong> Kommazahlen mit Nachkommastellen (z.B. <code>3.14</code>, <code>-0.5</code>, <code>2.0</code>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Wichtig: Punkt statt Komma!</div>
|
||||
Im Deutschen schreiben wir <code>3,14</code> mit Komma. Im Programmieren gilt immer der <strong>angelsächsische Punkt</strong>: <code>3.14</code>. Ein Komma in Python trennt Parameter oder Listenelemente!
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Die 7 Rechenoperatoren -->
|
||||
<section class="card">
|
||||
<h2>3. Die 7 Rechenoperatoren im Überblick</h2>
|
||||
<p>
|
||||
Hier sind alle wichtigen mathematischen Operatoren, die du in Python beherrschen musst:
|
||||
</p>
|
||||
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 15px 0;">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light); text-align: left;">
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Operator</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Name</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Beispiel</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Ergebnis</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Erklärung & Besonderheit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">+</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Addition</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>12 + 8</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;"><code>20</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Addiert zwei Werte</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">-</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Subtraktion</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>20 - 7</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;"><code>13</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Zieht den zweiten Wert ab</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">*</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Multiplikation</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>6 * 7</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;"><code>42</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Multipliziert zwei Werte</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">/</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Echte Division</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>7 / 2</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; color: #d97706;"><code>3.5</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Wichtig:</strong> Liefert in Python 3 <em>immer</em> ein <code>float</code> (Kommazahl)! Sogar <code>4 / 2</code> liefert <code>2.0</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">//</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Ganzzahldivision</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>17 // 5</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; color: var(--success);"><code>3</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Rundet das Ergebnis immer zur nächsten ganzen Zahl nach unten ab (Floor Division).</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">%</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Modulo (Rest)</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>17 % 5</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; color: var(--purple);"><code>2</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Gibt den <strong>Rest</strong> bei der Ganzzahldivision zurück.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold; font-family: var(--font-mono); color: var(--primary);">**</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Potenzierung</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>2 ** 3</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;"><code>8</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Berechnet Basis hoch Exponent (2 * 2 * 2 = 8).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>🍕 Die Pizza-Analogie für <code>//</code> und <code>%</code></h3>
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">17 Pizzastücke auf 5 Freunde aufteilen:</div>
|
||||
<p>
|
||||
- <code>17 // 5 = 3</code> → Jeder Freund bekommt genau <strong>3 ganze Stücke</strong>.<br>
|
||||
- <code>17 % 5 = 2</code> → In der Schachtel bleiben <strong>2 Stücke übrig</strong>.<br>
|
||||
- <em>Kontrollrechnung:</em> \(3 \times 5 + 2 = 17\) Stücke!
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Vorrangregeln -->
|
||||
<section class="card">
|
||||
<h2>4. Vorrangregeln: Punkt vor Strich & Klammern 📐</h2>
|
||||
<p>
|
||||
Python hält sich streng an die mathematischen Rechengesetze (PEMDAS):
|
||||
</p>
|
||||
|
||||
<ol style="margin-left: 25px; margin-bottom: 15px; line-height: 1.8;">
|
||||
<li><strong>Klammern <code>(...)</code>:</strong> Höchste Priorität – wird immer zuerst ausgewertet!</li>
|
||||
<li><strong>Potenzen <code>**</code>:</strong> Werden vor Punkt- und Strichrechnung ausgeführt.</li>
|
||||
<li><strong>Punktrechnung <code>*</code>, <code>/</code>, <code>//</code>, <code>%</code>:</strong> Kommt vor Strichrechnung.</li>
|
||||
<li><strong>Strichrechnung <code>+</code>, <code>-</code>:</strong> Wird zuletzt ausgeführt.</li>
|
||||
</ol>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Vergleich: Vorrangregeln</span>
|
||||
</div>
|
||||
<pre><span class="cm"># Ohne Klammer: 3 * 4 = 12, dann 2 + 12 = 14</span>
|
||||
<span class="var">a</span> = <span class="num">2</span> + <span class="num">3</span> * <span class="num">4</span> <span class="cm"># 14</span>
|
||||
|
||||
<span class="cm"># Mit Klammer: (2 + 3) = 5, dann 5 * 4 = 20</span>
|
||||
<span class="var">b</span> = (<span class="num">2</span> + <span class="num">3</span>) * <span class="num">4</span> <span class="cm"># 20</span>
|
||||
|
||||
<span class="cm"># Kreisflächen-Formel: pi * r²</span>
|
||||
<span class="var">flaeche</span> = <span class="num">3.14159</span> * (<span class="var">radius</span> ** <span class="num">2</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Textausgabe mit print() -->
|
||||
<section class="card">
|
||||
<h2>5. Erste Textausgaben mit <code>print()</code> 📢</h2>
|
||||
<p>
|
||||
Mit der eingebauten Python-Funktion <code>print()</code> gibst du Texte und Rechenergebnisse auf der Konsole aus:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Beispiele für print()</span></div>
|
||||
<pre><span class="fn">print</span>(<span class="str">"Hallo Welt!"</span>)
|
||||
<span class="fn">print</span>(<span class="str">"Das Ergebnis von 5 + 3 ist:"</span>, <span class="num">5</span> + <span class="num">3</span>)
|
||||
|
||||
<span class="cm"># Modern mit f-String:</span>
|
||||
<span class="var">radius</span> = <span class="num">5</span>
|
||||
<span class="var">flaeche</span> = <span class="num">3.14159</span> * (<span class="var">radius</span> ** <span class="num">2</span>)
|
||||
<span class="fn">print</span>(<span class="str">f"Kreis mit Radius {radius} hat die Fläche: {flaeche}"</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. Aufgabenblatt -->
|
||||
<section class="card">
|
||||
<h2>6. 📝 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
<p>
|
||||
Öffne die Datei <code>g01_erste_schritte_taschenrechner/aufgabe.py</code> in deinem Editor und bearbeite die 7 TODOs:
|
||||
</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>addieren(a, b)</code></strong> – Gib die Summe <code>a + b</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>subtrahieren(a, b)</code></strong> – Gib die Differenz <code>a - b</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>multiplizieren(a, b)</code></strong> – Gib das Produkt <code>a * b</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>dividieren(a, b)</code></strong> – Gib den Quotienten <code>a / b</code> zurück (liefert float).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5">
|
||||
<label for="t5" class="task-label">
|
||||
<strong>TODO 5: <code>ganzzahl_rest(a, b)</code></strong> – Gib ein Tupel <code>(a // b, a % b)</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6">
|
||||
<label for="t6" class="task-label">
|
||||
<strong>TODO 6: <code>potenz(basis, exponent)</code></strong> – Gib <code>basis ** exponent</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7">
|
||||
<label for="t7" class="task-label">
|
||||
<strong>TODO 7: <code>kreis_flaeche(radius)</code></strong> – Berechne <code>3.14159 * (radius ** 2)</code> und gib das Ergebnis zurück.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 5 (Tupel als Rückgabewert)</summary>
|
||||
<div class="details-content">
|
||||
<p>In Python kannst du zwei Werte auf einmal als Tupel zurückgeben, indem du sie mit einem Komma in runden Klammern schreibst:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">return</span> (<span class="var">a</span> // <span class="var">b</span>, <span class="var">a</span> % <span class="var">b</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 7 (Kreisfläche)</summary>
|
||||
<div class="details-content">
|
||||
<p>Verwende für Pi den vorgegebenen Wert <code>3.14159</code> und den Potenzoperator <code>** 2</code>:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">return</span> <span class="num">3.14159</span> * (<span class="var">radius</span> ** <span class="num">2</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 7. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>7. 🧪 Testen im Terminal</h2>
|
||||
<p>Führe das Testskript aus, um deine Funktionen automatisch zu überprüfen:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../index.html" class="btn btn-secondary">← Zurück zur Übersicht</a>
|
||||
<a href="../g02_variablen_und_datentypen/index.html" class="btn">Weiter zu Kapitel G02: Variablen & Datentypen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
53
g01_erste_schritte_taschenrechner/musterloesung.py
Normal file
53
g01_erste_schritte_taschenrechner/musterloesung.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""
|
||||
Grundlagen 01: Python als Taschenrechner – Musterlösung
|
||||
========================================================
|
||||
|
||||
Vollständige Referenzlösung für alle Rechenoperationen.
|
||||
"""
|
||||
|
||||
def addieren(a: float, b: float) -> float:
|
||||
"""Berechnet die Summe von a und b."""
|
||||
return a + b
|
||||
|
||||
|
||||
def subtrahieren(a: float, b: float) -> float:
|
||||
"""Berechnet die Differenz a - b."""
|
||||
return a - b
|
||||
|
||||
|
||||
def multiplizieren(a: float, b: float) -> float:
|
||||
"""Berechnet das Produkt von a und b."""
|
||||
return a * b
|
||||
|
||||
|
||||
def dividieren(a: float, b: float) -> float:
|
||||
"""Berechnet den Quotienten a / b als float."""
|
||||
return a / b
|
||||
|
||||
|
||||
def ganzzahl_rest(a: int, b: int) -> tuple:
|
||||
"""Gibt ein Tupel (ganzzahliger_quotient, rest) zurück."""
|
||||
return (a // b, a % b)
|
||||
|
||||
|
||||
def potenz(basis: float, exponent: float) -> float:
|
||||
"""Berechnet basis hoch exponent."""
|
||||
return basis ** exponent
|
||||
|
||||
|
||||
def kreis_flaeche(radius: float) -> float:
|
||||
"""Berechnet die Kreisfläche für den gegebenen Radius (pi = 3.14159)."""
|
||||
return 3.14159 * (radius ** 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 50)
|
||||
print("🧮 MUSTERLÖSUNG: G01 TASCHENRECHNER")
|
||||
print("=" * 50)
|
||||
print("addieren(12, 8) =", addieren(12, 8))
|
||||
print("subtrahieren(20, 7) =", subtrahieren(20, 7))
|
||||
print("multiplizieren(6, 7) =", multiplizieren(6, 7))
|
||||
print("dividieren(15, 2) =", dividieren(15, 2))
|
||||
print("ganzzahl_rest(17, 5) =", ganzzahl_rest(17, 5))
|
||||
print("potenz(2, 8) =", potenz(2, 8))
|
||||
print("kreis_flaeche(5) =", kreis_flaeche(5))
|
||||
127
g01_erste_schritte_taschenrechner/test_aufgabe.py
Normal file
127
g01_erste_schritte_taschenrechner/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import unittest
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das Verzeichnis im Python-Suchpfad liegt
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
|
||||
class TestKapitelG01(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Ermöglicht das Testen alternativer Module (z.B. musterloesung)
|
||||
if hasattr(cls, "modul_name"):
|
||||
cls.mod = importlib.import_module(cls.modul_name)
|
||||
else:
|
||||
try:
|
||||
cls.mod = importlib.import_module("aufgabe")
|
||||
except SyntaxError as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"SyntaxError in 'aufgabe.py': {e}. Überprüfe Doppelpunkte und Klammern!"
|
||||
except Exception as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"Fehler beim Import von 'aufgabe.py': {e}"
|
||||
|
||||
def _get_modul(self):
|
||||
if getattr(self, "mod", None) is None:
|
||||
err = getattr(self, "import_error", "aufgabe.py konnte nicht importiert werden")
|
||||
self.fail(f"❌ {err}")
|
||||
return self.mod
|
||||
|
||||
def test_01_addieren(self):
|
||||
"""Prüft die Funktion addieren(a, b)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "addieren"), "Fehler: Die Funktion 'addieren' fehlt noch!")
|
||||
self.assertEqual(mod.addieren(5, 3), 8, "addieren(5, 3) muss 8 ergeben!")
|
||||
self.assertEqual(mod.addieren(-4, 9), 5, "addieren(-4, 9) muss 5 ergeben!")
|
||||
self.assertEqual(mod.addieren(0, 0), 0, "addieren(0, 0) muss 0 ergeben!")
|
||||
self.assertAlmostEqual(mod.addieren(2.5, 1.5), 4.0, places=4, msg="addieren(2.5, 1.5) muss 4.0 ergeben!")
|
||||
|
||||
def test_02_subtrahieren(self):
|
||||
"""Prüft die Funktion subtrahieren(a, b)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "subtrahieren"), "Fehler: Die Funktion 'subtrahieren' fehlt noch!")
|
||||
self.assertEqual(mod.subtrahieren(10, 4), 6, "subtrahieren(10, 4) muss 6 ergeben!")
|
||||
self.assertEqual(mod.subtrahieren(3, 5), -2, "subtrahieren(3, 5) muss -2 ergeben!")
|
||||
self.assertEqual(mod.subtrahieren(7, 7), 0, "subtrahieren(7, 7) muss 0 ergeben!")
|
||||
self.assertAlmostEqual(mod.subtrahieren(5.5, 2.3), 3.2, places=4, msg="subtrahieren(5.5, 2.3) muss 3.2 ergeben!")
|
||||
|
||||
def test_03_multiplizieren(self):
|
||||
"""Prüft die Funktion multiplizieren(a, b)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "multiplizieren"), "Fehler: Die Funktion 'multiplizieren' fehlt noch!")
|
||||
self.assertEqual(mod.multiplizieren(6, 7), 42, "multiplizieren(6, 7) muss 42 ergeben!")
|
||||
self.assertEqual(mod.multiplizieren(-3, 4), -12, "multiplizieren(-3, 4) muss -12 ergeben!")
|
||||
self.assertEqual(mod.multiplizieren(99, 0), 0, "multiplizieren(99, 0) muss 0 ergeben!")
|
||||
self.assertAlmostEqual(mod.multiplizieren(4, 0.5), 2.0, places=4, msg="multiplizieren(4, 0.5) muss 2.0 ergeben!")
|
||||
|
||||
def test_04_dividieren(self):
|
||||
"""Prüft die Funktion dividieren(a, b)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "dividieren"), "Fehler: Die Funktion 'dividieren' fehlt noch!")
|
||||
self.assertEqual(mod.dividieren(10, 2), 5.0, "dividieren(10, 2) muss 5.0 ergeben!")
|
||||
self.assertEqual(mod.dividieren(7, 2), 3.5, "dividieren(7, 2) muss 3.5 ergeben!")
|
||||
self.assertEqual(mod.dividieren(-9, 3), -3.0, "dividieren(-9, 3) muss -3.0 ergeben!")
|
||||
self.assertAlmostEqual(mod.dividieren(1, 3), 0.333333, places=4, msg="dividieren(1, 3) sollte ca. 0.3333 ergeben!")
|
||||
|
||||
def test_05_ganzzahl_rest(self):
|
||||
"""Prüft die Funktion ganzzahl_rest(a, b) für Ganzzahldivision // und Modulo %."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "ganzzahl_rest"), "Fehler: Die Funktion 'ganzzahl_rest' fehlt noch!")
|
||||
|
||||
ergebnis1 = mod.ganzzahl_rest(17, 5)
|
||||
self.assertIsInstance(ergebnis1, tuple, "ganzzahl_rest muss ein Tupel (quotient, rest) zurückgeben!")
|
||||
self.assertEqual(len(ergebnis1), 2, "Das zurückgegebene Tupel muss genau 2 Elemente haben: (quotient, rest)")
|
||||
self.assertEqual(ergebnis1[0], 3, "17 // 5 ergibt den Quotienten 3!")
|
||||
self.assertEqual(ergebnis1[1], 2, "17 % 5 ergibt den Rest 2!")
|
||||
|
||||
ergebnis2 = mod.ganzzahl_rest(20, 4)
|
||||
self.assertEqual(ergebnis2, (5, 0), "ganzzahl_rest(20, 4) muss (5, 0) ergeben!")
|
||||
|
||||
ergebnis3 = mod.ganzzahl_rest(7, 3)
|
||||
self.assertEqual(ergebnis3, (2, 1), "ganzzahl_rest(7, 3) muss (2, 1) ergeben!")
|
||||
|
||||
ergebnis4 = mod.ganzzahl_rest(4, 9)
|
||||
self.assertEqual(ergebnis4, (0, 4), "ganzzahl_rest(4, 9) muss (0, 4) ergeben!")
|
||||
|
||||
def test_06_potenz(self):
|
||||
"""Prüft die Funktion potenz(basis, exponent)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "potenz"), "Fehler: Die Funktion 'potenz' fehlt noch!")
|
||||
self.assertEqual(mod.potenz(2, 3), 8, "potenz(2, 3) muss 8 ergeben (2 ** 3 = 8)!")
|
||||
self.assertEqual(mod.potenz(5, 2), 25, "potenz(5, 2) muss 25 ergeben (5 ** 2 = 25)!")
|
||||
self.assertEqual(mod.potenz(10, 0), 1, "potenz(10, 0) muss 1 ergeben (jede Zahl hoch 0 ist 1)!")
|
||||
self.assertEqual(mod.potenz(3, 4), 81, "potenz(3, 4) muss 81 ergeben!")
|
||||
self.assertAlmostEqual(mod.potenz(4, 0.5), 2.0, places=4, msg="potenz(4, 0.5) muss 2.0 (Quadratwurzel) ergeben!")
|
||||
|
||||
def test_07_kreis_flaeche(self):
|
||||
"""Prüft die Funktion kreis_flaeche(radius) mit pi = 3.14159."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "kreis_flaeche"), "Fehler: Die Funktion 'kreis_flaeche' fehlt noch!")
|
||||
|
||||
erg1 = mod.kreis_flaeche(1)
|
||||
self.assertIsNotNone(erg1, "kreis_flaeche(1) gibt None zurück. Vergiss nicht das 'return'!")
|
||||
self.assertAlmostEqual(
|
||||
erg1, 3.14159, places=4,
|
||||
msg="kreis_flaeche(1) muss 3.14159 ergeben!"
|
||||
)
|
||||
|
||||
erg2 = mod.kreis_flaeche(2)
|
||||
self.assertIsNotNone(erg2, "kreis_flaeche(2) gibt None zurück. Vergiss nicht das 'return'!")
|
||||
self.assertAlmostEqual(
|
||||
erg2, 12.56636, places=4,
|
||||
msg="kreis_flaeche(2) muss 12.56636 ergeben!"
|
||||
)
|
||||
|
||||
erg0 = mod.kreis_flaeche(0)
|
||||
self.assertIsNotNone(erg0, "kreis_flaeche(0) gibt None zurück. Vergiss nicht das 'return'!")
|
||||
self.assertAlmostEqual(
|
||||
erg0, 0.0, places=4,
|
||||
msg="kreis_flaeche(0) muss 0.0 ergeben!"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
124
g02_variablen_und_datentypen/README.md
Normal file
124
g02_variablen_und_datentypen/README.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# Grundlagen 02: Variablen & Datentypen 📦🏷️ (Schulabgleich 03.0 & 03.1)
|
||||
|
||||
In diesem Kapitel lernst du, wie Python Daten im Arbeitsspeicher speichert, welche 4 Basisdatentypen es gibt, wie Type Hints funktionieren und wie du Typen sicher umwandelst (Type Casting).
|
||||
|
||||
---
|
||||
|
||||
## 📦 1. Was ist eine Variable? (Die Speicherbox-Analogie)
|
||||
|
||||
Stell dir den Arbeitsspeicher deines Computers wie ein großes Lagerregal voller **Aufbewahrungsboxen** vor:
|
||||
- Der **Wert** (z.B. `18` oder `"Anna"`) liegt in der Box.
|
||||
- Die **Variable** ist das **Namensschild / Etikett**, das du außen an die Box klebst.
|
||||
- Über das Etikett kannst du jederzeit auf den Inhalt zugreifen oder einen neuen Wert hineinlegen!
|
||||
|
||||
```python
|
||||
# Zuweisungs-Operator '=' klebt das Etikett 'alter' an den Wert 16:
|
||||
alter = 16
|
||||
|
||||
# Später Geburtstag feiern – Wert in der Box aktualisieren:
|
||||
alter = alter + 1 # Jetzt ist alter 17!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 2. Die 4 Basisdatentypen in Python
|
||||
|
||||
Python besitzt 4 grundlegende Datentypen, die du blind beherrschen musst:
|
||||
|
||||
| Datentyp | Deutscher Begriff | Python-Typ | Beispiele | Erklärung |
|
||||
| :--- | :--- | :---: | :--- | :--- |
|
||||
| **Ganzzahl** | Ganze Zahl | `int` | `42`, `-7`, `0`, `1000` | Zahlen ohne Kommastelle |
|
||||
| **Kommazahl** | Gleitkommazahl | `float` | `3.14`, `-0.5`, `2.0` | Zahlen mit Dezimalpunkt `.` |
|
||||
| **Text** | Zeichenkette / String | `str` | `"Hallo"`, `'Python'`, `"123"` | Zeichen in einfachen `'` oder doppelten `"` Anführungszeichen |
|
||||
| **Wahrheitswert** | Boolescher Wert | `bool` | `True`, `False` | Genau zwei Zustände: Wahr oder Falsch |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 3. Typprüfung mit `type()` & Moderne Type Hints
|
||||
|
||||
### Typ abfragen:
|
||||
Mit der Funktion `type(wert)` kannst du herausfinden, welcher Datentyp vorliegt:
|
||||
```python
|
||||
print(type(42)) # <class 'int'>
|
||||
print(type(3.14)) # <class 'float'>
|
||||
print(type("Hallo")) # <class 'str'>
|
||||
print(type(True)) # <class 'bool'>
|
||||
```
|
||||
|
||||
### Type Hints (Typ-Annotationen):
|
||||
In modernem Python (und in deinem Schulskriptum!) dokumentieren wir Variablen und Funktionsparameter mit Typ-Hinweisen:
|
||||
```python
|
||||
name: str = "Alice"
|
||||
alter: int = 16
|
||||
preis: float = 19.99
|
||||
ist_aktiv: bool = True
|
||||
|
||||
def begruessen(benutzer: str, wiederholungen: int) -> str:
|
||||
return (benutzer + "! ") * wiederholungen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 4. Typumwandlung (Type Casting)
|
||||
|
||||
Manchmal liegt ein Wert im falschen Format vor (z.B. `"42"` als Text statt Zahl). Mit den Typ-Funktionen kannst du Daten umwandeln:
|
||||
|
||||
```python
|
||||
# Text zu Ganzzahl:
|
||||
zahl = int("42") # 42 (int)
|
||||
|
||||
# Text zu Kommazahl:
|
||||
pi = float("3.14") # 3.14 (float)
|
||||
|
||||
# Zahl zu Text:
|
||||
text = str(100) # "100" (str)
|
||||
|
||||
# Zu Wahrheitswert (bool):
|
||||
b1 = bool(1) # True (alles außer 0 ist True)
|
||||
b2 = bool(0) # False
|
||||
b3 = bool("") # False (leerer String ist False)
|
||||
b4 = bool("Python") # True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 5. Die klassische Anfängerfalle: `"10" + "20"` vs. `10 + 20`
|
||||
|
||||
Der Plus-Operator `+` verhält sich bei Texten ganz anders als bei Zahlen!
|
||||
|
||||
```python
|
||||
# ❌ Text-Verkettung (String-Konkatenation):
|
||||
ergebnis_text = "10" + "20"
|
||||
print(ergebnis_text) # Ausgabe: "1020"
|
||||
|
||||
# ✅ Mathematische Addition:
|
||||
ergebnis_zahl = 10 + 20
|
||||
print(ergebnis_zahl) # Ausgabe: 30
|
||||
|
||||
# ✅ Aus Texten echte Zahlen machen vor der Addition:
|
||||
text_a = "10"
|
||||
text_b = "20"
|
||||
richtig = int(text_a) + int(text_b)
|
||||
print(richtig) # Ausgabe: 30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne die Datei `aufgabe.py` und bearbeite die folgenden 4 TODOs:
|
||||
1. **TODO 1: `bestimme_typ_name(wert)`** $\rightarrow$ Gibt `"Wahrheitswert"`, `"Ganzzahl"`, `"Kommazahl"`, `"Text"` oder `"Unbekannt"` zurück.
|
||||
2. **TODO 2: `summe_aus_texten(text_a, text_b)`** $\rightarrow$ Wandelt zwei Zahlen-Strings in `int` um und gibt die mathematische Summe zurück.
|
||||
3. **TODO 3: `formatiere_preis(preis_float)`** $\rightarrow$ Formatiert einen Preis auf 2 Nachkommastellen mit Euro-Zeichen (z.B. `19.99 €`).
|
||||
4. **TODO 4: `ist_volljaehrig(alter) -> bool`** $\rightarrow$ Gibt `True` ab 18 Jahren zurück, sonst `False`.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Lösung überprüfen
|
||||
|
||||
Führe im Terminal den automatischen Unittest aus:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
|
||||
Wenn alle 4 Tests mit `OK` durchlaufen, hast du die Grundlagen von Variablen und Datentypen gemeistert! 🎉
|
||||
121
g02_variablen_und_datentypen/aufgabe.py
Normal file
121
g02_variablen_und_datentypen/aufgabe.py
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
"""
|
||||
Grundlagen 02: Variablen & Datentypen – Aufgabenblatt
|
||||
======================================================
|
||||
|
||||
In diesem Kapitel lernst du, wie Variablen als benannte Speicherboxen
|
||||
funktionieren, welche 4 Basisdatentypen Python besitzt und wie du Typen
|
||||
umwandelst (Type Casting).
|
||||
|
||||
Bearbeite die Aufgaben Schritt für Schritt von TODO 1 bis TODO 4.
|
||||
Wenn du fertig bist, überprüfe deine Lösung im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Schreibe die Funktion 'bestimme_typ_name(wert)'
|
||||
#
|
||||
# Die Funktion bekommt einen beliebigen Wert übergeben und soll als String
|
||||
# den deutschen Namen des Datentyps zurückgeben:
|
||||
# - Wenn 'wert' ein bool ist (True/False): -> "Wahrheitswert"
|
||||
# - Wenn 'wert' ein int ist (z.B. 42): -> "Ganzzahl"
|
||||
# - Wenn 'wert' ein float ist (z.B. 3.14): -> "Kommazahl"
|
||||
# - Wenn 'wert' ein str ist (z.B. "Hallo"): -> "Text"
|
||||
# - Bei allen anderen Typen: -> "Unbekannt"
|
||||
#
|
||||
# WICHTIGER HINWEIS:
|
||||
# In Python ist 'bool' eine Unterklasse von 'int' (isinstance(True, int) ist True!).
|
||||
# Prüfe daher 'bool' ZUERST vor 'int' oder verwende 'type(wert) is bool'!
|
||||
#
|
||||
# Beispiele:
|
||||
# bestimme_typ_name(42) -> "Ganzzahl"
|
||||
# bestimme_typ_name(3.14) -> "Kommazahl"
|
||||
# bestimme_typ_name("Python") -> "Text"
|
||||
# bestimme_typ_name(True) -> "Wahrheitswert"
|
||||
# ==============================================================================
|
||||
|
||||
def bestimme_typ_name(wert) -> str:
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schreibe die Funktion 'summe_aus_texten(text_a, text_b)'
|
||||
#
|
||||
# Oft kommen Benutzereingaben (z.B. von input()) als Text (str) an.
|
||||
# Wenn man "10" + "20" rechnet, entsteht fälschlicherweise "1020" (Textverkettung).
|
||||
#
|
||||
# Deine Aufgabe:
|
||||
# Wandle beide Parameter 'text_a' und 'text_b' mit 'int()' in echte Ganzzahlen um,
|
||||
# addiere sie mathematisch und gib das Ergebnis (als int) zurück!
|
||||
#
|
||||
# Beispiele:
|
||||
# summe_aus_texten("10", "20") -> 30 (nicht "1020"!)
|
||||
# summe_aus_texten("5", "7") -> 12
|
||||
# ==============================================================================
|
||||
|
||||
def summe_aus_texten(text_a: str, text_b: str) -> int:
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schreibe die Funktion 'formatiere_preis(preis_float)'
|
||||
#
|
||||
# Die Funktion bekommt einen Preis als float (Kommazahl) übergeben und soll
|
||||
# einen formatierten String mit genau 2 Nachkommastellen und dem Euro-Zeichen '€'
|
||||
# zurückgeben.
|
||||
#
|
||||
# Format: "{preis:.2f} €"
|
||||
#
|
||||
# Beispiele:
|
||||
# formatiere_preis(19.99) -> "19.99 €"
|
||||
# formatiere_preis(5.0) -> "5.00 €"
|
||||
# formatiere_preis(0.0) -> "0.00 €"
|
||||
# ==============================================================================
|
||||
|
||||
def formatiere_preis(preis_float: float) -> str:
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Schreibe die Funktion 'ist_volljaehrig(alter)'
|
||||
#
|
||||
# Die Funktion bekommt ein Alter als Ganzzahl übergeben.
|
||||
# Sie soll 'True' zurückgeben, wenn 'alter' größer oder gleich 18 ist,
|
||||
# andernfalls 'False'.
|
||||
#
|
||||
# Tipp:
|
||||
# Ein Vergleichsoperator wie 'alter >= 18' liefert bereits direkt einen bool!
|
||||
#
|
||||
# Beispiele:
|
||||
# ist_volljaehrig(18) -> True
|
||||
# ist_volljaehrig(21) -> True
|
||||
# ist_volljaehrig(17) -> False
|
||||
# ==============================================================================
|
||||
|
||||
def ist_volljaehrig(alter: int) -> bool:
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Führe diese Datei direkt aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 55)
|
||||
print("📦 VARIABLEN & DATENTYPEN – TEST-AUSGABE")
|
||||
print("=" * 55)
|
||||
|
||||
print("Typ von 42: ", bestimme_typ_name(42))
|
||||
print("Typ von 3.14: ", bestimme_typ_name(3.14))
|
||||
print("Typ von 'Hallo': ", bestimme_typ_name("Hallo"))
|
||||
print("Typ von True: ", bestimme_typ_name(True))
|
||||
|
||||
print("\nSumme aus '10' + '20':", summe_aus_texten("10", "20"))
|
||||
print("Preis formatiert (19.9):", formatiere_preis(19.9))
|
||||
print("Ist 17 volljährig? ", ist_volljaehrig(17))
|
||||
print("Ist 18 volljährig? ", ist_volljaehrig(18))
|
||||
|
||||
print("\n💡 Führe 'python3 test_aufgabe.py' aus, um deine Lösungen zu prüfen!")
|
||||
256
g02_variablen_und_datentypen/index.html
Normal file
256
g02_variablen_und_datentypen/index.html
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Grundlagen 02: Variablen & Datentypen</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../g01_erste_schritte_taschenrechner/index.html">← Grundlagen 01</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html">🏠 Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Grundlagen 02</span>
|
||||
<span>›</span>
|
||||
<a href="../g03_ein_und_ausgabe/index.html">Grundlagen 03 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen 02 • Schulabgleich 03.0 & 03.1</div>
|
||||
<h1>Variablen & Datentypen 📦🏷️</h1>
|
||||
<p>Lerne, wie Daten im Arbeitsspeicher abgelegt werden, was <code>int</code>, <code>float</code>, <code>str</code> und <code>bool</code> unterscheidet und wie Type Casting funktioniert.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie: Die Speicherbox -->
|
||||
<section class="card">
|
||||
<h2>1. Was ist eine Variable? (Die Speicherbox-Analogie) 📦</h2>
|
||||
<p>
|
||||
Programme müssen Zwischenergebnisse, Spielstände oder Benutzernamen speichern. Dafür nutzt man <strong>Variablen</strong>.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏷️ Das Namensschild am Karton:</div>
|
||||
Stell dir den Arbeitsspeicher (RAM) deines Computers wie ein gigantisches Regal voller Kartons vor:
|
||||
<ul style="margin-left: 20px; margin-top: 6px;">
|
||||
<li>Der <strong>Wert</strong> (z.B. <code>16</code> oder <code>"Mia"</code>) liegt im Karton.</li>
|
||||
<li>Der <strong>Variablenname</strong> (z.B. <code>alter</code>) ist das Etikett, das du außen auf den Karton klebst.</li>
|
||||
<li>Mit dem Zuweisungsoperator <code>=</code> legst du einen Wert in den Karton hinein!</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Variablen zuweisen und verändern</span></div>
|
||||
<pre><span class="cm"># Wert 16 in die Box 'alter' legen:</span>
|
||||
<span class="var">alter</span> = <span class="num">16</span>
|
||||
|
||||
<span class="cm"># Später Geburtstag feiern – Wert aktualisieren:</span>
|
||||
<span class="var">alter</span> = <span class="var">alter</span> + <span class="num">1</span> <span class="cm"># Jetzt ist alter 17!</span>
|
||||
|
||||
<span class="fn">print</span>(<span class="str">"Neues Alter:"</span>, <span class="var">alter</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Die 4 Basisdatentypen -->
|
||||
<section class="card">
|
||||
<h2>2. Die 4 Basisdatentypen in Python 🏷️</h2>
|
||||
<p>
|
||||
Jeder Wert in Python gehört zu einer bestimmten Datenkategorie (einem sogenannten <strong>Datentyp</strong>):
|
||||
</p>
|
||||
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 15px 0;">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light); text-align: left;">
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Datentyp</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Python-Typ</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Beispiele</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Erklärung & Verwendung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;">Ganzzahl</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-family: var(--font-mono); color: var(--primary); font-weight: bold;">int</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>42</code>, <code>-7</code>, <code>0</code>, <code>1000</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Zähler, Alter, Punkte im Spiel (ohne Nachkommastellen).</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;">Kommazahl</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-family: var(--font-mono); color: var(--primary); font-weight: bold;">float</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>3.14</code>, <code>-0.5</code>, <code>2.0</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Preise, Messwerte, Notendurchschnitt (mit Dezimalpunkt <code>.</code>).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;">Text (String)</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-family: var(--font-mono); color: var(--primary); font-weight: bold;">str</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>"Hallo"</code>, <code>'Python'</code>, <code>"42"</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Namen, Nachrichten, Adressen (immer in Anführungszeichen).</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-weight: bold;">Wahrheitswert</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color); font-family: var(--font-mono); color: var(--primary); font-weight: bold;">bool</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>True</code>, <code>False</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Logische Schalter, Bedingungen, Berechtigungen (z.B. Volljährigkeit).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- 3. Typprüfung & Type Hints -->
|
||||
<section class="card">
|
||||
<h2>3. Typprüfung mit <code>type()</code> & Moderne Type Hints 🔍</h2>
|
||||
|
||||
<p>Mit der eingebauten Funktion <code>type()</code> kannst du Python fragen, welchen Typ ein Wert hat:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>type() Abfragen</span></div>
|
||||
<pre><span class="fn">print</span>(<span class="fn">type</span>(<span class="num">42</span>)) <span class="cm"># <class 'int'></span>
|
||||
<span class="fn">print</span>(<span class="fn">type</span>(<span class="num">3.14</span>)) <span class="cm"># <class 'float'></span>
|
||||
<span class="fn">print</span>(<span class="fn">type</span>(<span class="str">"Mia"</span>)) <span class="cm"># <class 'str'></span>
|
||||
<span class="fn">print</span>(<span class="fn">type</span>(<span class="kw">True</span>)) <span class="cm"># <class 'bool'></span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">📝 Type Hints (Typ-Hinweise nach Schulstandard):</div>
|
||||
Im Unterricht und in professionellen Codebases kennzeichnen wir Variablen und Funktions-Signaturen mit Typen. Das hilft VS Code und Lesern enorm beim Verstehen des Codes!
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Type Hints in Aktion</span></div>
|
||||
<pre><span class="var">name</span>: <span class="kw">str</span> = <span class="str">"Alice"</span>
|
||||
<span class="var">alter</span>: <span class="kw">int</span> = <span class="num">17</span>
|
||||
<span class="var">kontostand</span>: <span class="kw">float</span> = <span class="num">149.50</span>
|
||||
<span class="var">ist_mitglied</span>: <span class="kw">bool</span> = <span class="kw">True</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">ist_volljaehrig</span>(<span class="var">alter</span>: <span class="kw">int</span>) -> <span class="kw">bool</span>:
|
||||
<span class="kw">return</span> <span class="var">alter</span> >= <span class="num">18</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Type Casting -->
|
||||
<section class="card">
|
||||
<h2>4. Typumwandlung (Type Casting) 🔄</h2>
|
||||
<p>
|
||||
Oft müssen wir Daten von einem Typ in einen anderen umwandeln (z.B. einen Text <code>"42"</code> in eine echte Zahl <code>42</code>, um damit rechnen zu können).
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Casting-Funktionen</span></div>
|
||||
<pre><span class="cm"># 1. In Ganzzahl umwandeln:</span>
|
||||
<span class="var">z1</span> = <span class="fn">int</span>(<span class="str">"42"</span>) <span class="cm"># 42</span>
|
||||
<span class="var">z2</span> = <span class="fn">int</span>(<span class="num">9.99</span>) <span class="cm"># 9 (schneidet Nachkommastellen einfach ab!)</span>
|
||||
|
||||
<span class="cm"># 2. In Kommazahl umwandeln:</span>
|
||||
<span class="var">f1</span> = <span class="fn">float</span>(<span class="str">"3.14"</span>) <span class="cm"># 3.14</span>
|
||||
<span class="var">f2</span> = <span class="fn">float</span>(<span class="num">10</span>) <span class="cm"># 10.0</span>
|
||||
|
||||
<span class="cm"># 3. In Text umwandeln:</span>
|
||||
<span class="var">s1</span> = <span class="fn">str</span>(<span class="num">100</span>) <span class="cm"># "100"</span>
|
||||
<span class="var">s2</span> = <span class="fn">str</span>(<span class="kw">True</span>) <span class="cm"># "True"</span>
|
||||
|
||||
<span class="cm"># 4. In Wahrheitswert (bool) umwandeln:</span>
|
||||
<span class="var">b1</span> = <span class="fn">bool</span>(<span class="num">1</span>) <span class="cm"># True (Zahlen != 0 sind True)</span>
|
||||
<span class="var">b2</span> = <span class="fn">bool</span>(<span class="num">0</span>) <span class="cm"># False</span>
|
||||
<span class="var">b3</span> = <span class="fn">bool</span>(<span class="str">""</span>) <span class="cm"># False (leerer Text ist False)</span>
|
||||
<span class="var">b4</span> = <span class="fn">bool</span>(<span class="str">"Hallo"</span>) <span class="cm"># True (nicht-leerer Text ist True)</span></pre>
|
||||
</div>
|
||||
|
||||
<!-- Warnung Anfängerfalle -->
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">💥 Der klassische Anfängerfehler: "10" + "20" vs. 10 + 20</div>
|
||||
<p>
|
||||
Wenn du zwei Strings mit <code>+</code> verbindest, werden sie aneinandergehängt (<strong>Konkatenation</strong>). Wenn du zwei Zahlen addierst, wird gerechnet:
|
||||
</p>
|
||||
<p style="margin-top: 6px; font-family: var(--font-mono);">
|
||||
- <code>"10" + "20"</code> → <code>"1020"</code> ❌ (Textverkettung!)<br>
|
||||
- <code>10 + 20</code> → <code>30</code> ✅ (Zahlenaddition!)<br>
|
||||
- <code>int("10") + int("20")</code> → <code>30</code> ✅ (Mit Casting!)
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Aufgabenblatt -->
|
||||
<section class="card">
|
||||
<h2>5. 📝 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
<p>
|
||||
Öffne die Datei <code>g02_variablen_und_datentypen/aufgabe.py</code> und bearbeite die 4 TODOs:
|
||||
</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>bestimme_typ_name(wert)</code></strong> – Gib <code>"Wahrheitswert"</code>, <code>"Ganzzahl"</code>, <code>"Kommazahl"</code>, <code>"Text"</code> oder <code>"Unbekannt"</code> zurück. <em>(Tipp: Prüfe <code>bool</code> vor <code>int</code>!)</em>
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>summe_aus_texten(text_a, text_b)</code></strong> – Wandle beide Textparameter mit <code>int()</code> um und addiere sie mathematisch.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>formatiere_preis(preis_float)</code></strong> – Formatiere den Preis mit 2 Nachkommastellen und Euro-Zeichen (z.B. <code>f"{preis_float:.2f} €"</code>).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>ist_volljaehrig(alter)</code></strong> – Gib <code>True</code> zurück, wenn <code>alter >= 18</code> ist, sonst <code>False</code>.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 1 (Die bool vs. int Falle)</summary>
|
||||
<div class="details-content">
|
||||
<p>In Python erbt <code>bool</code> historisch von <code>int</code>. Wenn du <code>isinstance(True, int)</code> ausführst, liefert Python <code>True</code>! Prüfe daher immer zuerst:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">if</span> <span class="fn">isinstance</span>(<span class="var">wert</span>, <span class="kw">bool</span>):
|
||||
<span class="kw">return</span> <span class="str">"Wahrheitswert"</span>
|
||||
<span class="kw">elif</span> <span class="fn">isinstance</span>(<span class="var">wert</span>, <span class="kw">int</span>):
|
||||
<span class="kw">return</span> <span class="str">"Ganzzahl"</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Kommazahlen mit f-String runden)</summary>
|
||||
<div class="details-content">
|
||||
<p>Mit <code>{preis:.2f}</code> wird eine Kommazahl auf exakt 2 Nachkommastellen formatiert:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">return</span> <span class="str">f"{preis_float:.2f} €"</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 6. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>6. 🧪 Testen im Terminal</h2>
|
||||
<p>Sobald du alle 4 Funktionen implementiert hast, führe den Unittest aus:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g01_erste_schritte_taschenrechner/index.html" class="btn btn-secondary">← Zurück zu G01: Taschenrechner</a>
|
||||
<a href="../g03_ein_und_ausgabe/index.html" class="btn">Weiter zu Kapitel G03: Ein- & Ausgabe →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
49
g02_variablen_und_datentypen/musterloesung.py
Normal file
49
g02_variablen_und_datentypen/musterloesung.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
"""
|
||||
Grundlagen 02: Variablen & Datentypen – Musterlösung
|
||||
=====================================================
|
||||
|
||||
Vollständige Referenzlösung für alle Aufgaben.
|
||||
"""
|
||||
|
||||
def bestimme_typ_name(wert) -> str:
|
||||
"""Gibt den deutschen Namen des Datentyps als String zurück."""
|
||||
# Wichtig: bool zuerst prüfen, da bool von int erbt!
|
||||
if isinstance(wert, bool):
|
||||
return "Wahrheitswert"
|
||||
elif isinstance(wert, int):
|
||||
return "Ganzzahl"
|
||||
elif isinstance(wert, float):
|
||||
return "Kommazahl"
|
||||
elif isinstance(wert, str):
|
||||
return "Text"
|
||||
else:
|
||||
return "Unbekannt"
|
||||
|
||||
|
||||
def summe_aus_texten(text_a: str, text_b: str) -> int:
|
||||
"""Wandelt zwei Zahlen-Strings in echte Integers um und berechnet deren Summe."""
|
||||
return int(text_a) + int(text_b)
|
||||
|
||||
|
||||
def formatiere_preis(preis_float: float) -> str:
|
||||
"""Formatiert einen Preis mit genau 2 Nachkommastellen und Euro-Zeichen."""
|
||||
return f"{preis_float:.2f} €"
|
||||
|
||||
|
||||
def ist_volljaehrig(alter: int) -> bool:
|
||||
"""Prüft, ob ein Alter >= 18 ist und gibt True/False zurück."""
|
||||
return alter >= 18
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 55)
|
||||
print("📦 MUSTERLÖSUNG: G02 VARIABLEN & DATENTYPEN")
|
||||
print("=" * 55)
|
||||
print("bestimme_typ_name(42) =", bestimme_typ_name(42))
|
||||
print("bestimme_typ_name(3.14) =", bestimme_typ_name(3.14))
|
||||
print("bestimme_typ_name('Python') =", bestimme_typ_name("Python"))
|
||||
print("bestimme_typ_name(True) =", bestimme_typ_name(True))
|
||||
print("summe_aus_texten('10', '20')=", summe_aus_texten("10", "20"))
|
||||
print("formatiere_preis(19.99) =", formatiere_preis(19.99))
|
||||
print("ist_volljaehrig(17) =", ist_volljaehrig(17))
|
||||
print("ist_volljaehrig(18) =", ist_volljaehrig(18))
|
||||
113
g02_variablen_und_datentypen/test_aufgabe.py
Normal file
113
g02_variablen_und_datentypen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import unittest
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das Verzeichnis im Python-Suchpfad liegt
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
|
||||
class TestKapitelG02(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Ermöglicht das Testen alternativer Module (z.B. musterloesung)
|
||||
if hasattr(cls, "modul_name"):
|
||||
cls.mod = importlib.import_module(cls.modul_name)
|
||||
else:
|
||||
try:
|
||||
cls.mod = importlib.import_module("aufgabe")
|
||||
except SyntaxError as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"SyntaxError in 'aufgabe.py': {e}. Überprüfe Doppelpunkte und Einrückungen!"
|
||||
except Exception as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"Fehler beim Import von 'aufgabe.py': {e}"
|
||||
|
||||
def _get_modul(self):
|
||||
if getattr(self, "mod", None) is None:
|
||||
err = getattr(self, "import_error", "aufgabe.py konnte nicht importiert werden")
|
||||
self.fail(f"❌ {err}")
|
||||
return self.mod
|
||||
|
||||
def test_01_bestimme_typ_name(self):
|
||||
"""Prüft die Funktion bestimme_typ_name(wert) für alle 4 Basisdatentypen und Unbekannt."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "bestimme_typ_name"), "Fehler: Die Funktion 'bestimme_typ_name' fehlt noch!")
|
||||
|
||||
# Ganze Zahlen (int)
|
||||
self.assertEqual(mod.bestimme_typ_name(42), "Ganzzahl", "42 muss als 'Ganzzahl' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name(0), "Ganzzahl", "0 muss als 'Ganzzahl' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name(-15), "Ganzzahl", "-15 muss als 'Ganzzahl' erkannt werden!")
|
||||
|
||||
# Kommazahlen (float)
|
||||
self.assertEqual(mod.bestimme_typ_name(3.14), "Kommazahl", "3.14 muss als 'Kommazahl' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name(0.0), "Kommazahl", "0.0 muss als 'Kommazahl' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name(-2.5), "Kommazahl", "-2.5 muss als 'Kommazahl' erkannt werden!")
|
||||
|
||||
# Text (str)
|
||||
self.assertEqual(mod.bestimme_typ_name("Hallo"), "Text", "'Hallo' muss als 'Text' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name(""), "Text", "Leerer String '' muss als 'Text' erkannt werden!")
|
||||
self.assertEqual(mod.bestimme_typ_name("123"), "Text", "'123' in Anführungszeichen ist 'Text'!")
|
||||
|
||||
# Wahrheitswerte (bool) - Besonderer Test: Darf nicht als Ganzzahl erkannt werden!
|
||||
self.assertEqual(
|
||||
mod.bestimme_typ_name(True), "Wahrheitswert",
|
||||
"True muss als 'Wahrheitswert' erkannt werden (nicht als 'Ganzzahl'!)"
|
||||
)
|
||||
self.assertEqual(
|
||||
mod.bestimme_typ_name(False), "Wahrheitswert",
|
||||
"False muss als 'Wahrheitswert' erkannt werden (nicht als 'Ganzzahl'!)"
|
||||
)
|
||||
|
||||
# Andere / Unbekannte Typen
|
||||
self.assertEqual(mod.bestimme_typ_name([1, 2, 3]), "Unbekannt", "Eine Liste sollte 'Unbekannt' liefern.")
|
||||
self.assertEqual(mod.bestimme_typ_name(None), "Unbekannt", "None sollte 'Unbekannt' liefern.")
|
||||
|
||||
def test_02_summe_aus_texten(self):
|
||||
"""Prüft die Typkonvertierung von Texten zu Integers und deren Addition."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "summe_aus_texten"), "Fehler: Die Funktion 'summe_aus_texten' fehlt noch!")
|
||||
|
||||
ergebnis = mod.summe_aus_texten("10", "20")
|
||||
self.assertIsNotNone(ergebnis, "summe_aus_texten('10', '20') liefert None. Vergiss nicht das 'return'!")
|
||||
self.assertNotEqual(
|
||||
ergebnis, "1020",
|
||||
"Achtung: Du hast '1020' als Text erhalten! Wandle die Strings mit int() um, bevor du addierst!"
|
||||
)
|
||||
self.assertIsInstance(ergebnis, int, "Das Ergebnis muss vom Typ 'int' sein!")
|
||||
self.assertEqual(ergebnis, 30, "summe_aus_texten('10', '20') muss 30 ergeben!")
|
||||
|
||||
self.assertEqual(mod.summe_aus_texten("5", "7"), 12, "summe_aus_texten('5', '7') muss 12 ergeben!")
|
||||
self.assertEqual(mod.summe_aus_texten("-3", "8"), 5, "summe_aus_texten('-3', '8') muss 5 ergeben!")
|
||||
self.assertEqual(mod.summe_aus_texten("0", "0"), 0, "summe_aus_texten('0', '0') muss 0 ergeben!")
|
||||
|
||||
def test_03_formatiere_preis(self):
|
||||
"""Prüft die Preisformatierung mit 2 Nachkommastellen und Euro-Symbol."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "formatiere_preis"), "Fehler: Die Funktion 'formatiere_preis' fehlt noch!")
|
||||
|
||||
self.assertEqual(mod.formatiere_preis(19.99), "19.99 €", "19.99 muss zu '19.99 €' formatiert werden!")
|
||||
self.assertEqual(mod.formatiere_preis(5.0), "5.00 €", "5.0 muss zu '5.00 €' (mit 2 Nullen) formatiert werden!")
|
||||
self.assertEqual(mod.formatiere_preis(0.0), "0.00 €", "0.0 muss zu '0.00 €' formatiert werden!")
|
||||
self.assertEqual(mod.formatiere_preis(149.5), "149.50 €", "149.5 muss zu '149.50 €' formatiert werden!")
|
||||
self.assertEqual(mod.formatiere_preis(3.14159), "3.14 €", "3.14159 muss auf 2 Nachkommastellen '3.14 €' gerundet werden!")
|
||||
|
||||
def test_04_ist_volljaehrig(self):
|
||||
"""Prüft die Funktion ist_volljaehrig(alter) für verschiedene Altersgrenzen."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(hasattr(mod, "ist_volljaehrig"), "Fehler: Die Funktion 'ist_volljaehrig' fehlt noch!")
|
||||
|
||||
# Volljährig
|
||||
self.assertIs(mod.ist_volljaehrig(18), True, "18 Jahre muss True (volljährig) sein!")
|
||||
self.assertIs(mod.ist_volljaehrig(21), True, "21 Jahre muss True sein!")
|
||||
self.assertIs(mod.ist_volljaehrig(50), True, "50 Jahre muss True sein!")
|
||||
|
||||
# Minderjährig
|
||||
self.assertIs(mod.ist_volljaehrig(17), False, "17 Jahre muss False (minderjährig) sein!")
|
||||
self.assertIs(mod.ist_volljaehrig(16), False, "16 Jahre muss False sein!")
|
||||
self.assertIs(mod.ist_volljaehrig(0), False, "0 Jahre muss False sein!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
122
g03_ein_und_ausgabe/README.md
Normal file
122
g03_ein_und_ausgabe/README.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Kapitel G03: Interaktive Ein- & Ausgabe (Schulabgleich 07.0) 💬⌨️
|
||||
|
||||
Herzlich willkommen zum Kapitel **Interaktive Ein- und Ausgabe**!
|
||||
|
||||
Programme werden erst dann richtig spannend, wenn sie mit Menschen interagieren können: Sie stellen Fragen, nehmen Antworten über die Tastatur entgegen, verarbeiten diese und geben schön formatierte Ergebnisse auf dem Bildschirm aus.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Lernziele
|
||||
|
||||
1. **Benutzereingaben erfassen:** `input("Fragetext: ")` nutzen.
|
||||
2. **Die goldene `input()`-Regel verstehen:** `input()` liefert **immer** einen `str` (Text), selbst wenn die Benutzerin `42` eingibt.
|
||||
3. **Datentypen umwandeln (Typkonvertierung / Casting):** Mit `int()` und `float()` Texte in Zahlen umwandeln.
|
||||
4. **Moderne f-Strings einsetzen:** Variablen und Ausdrücke sauber in Texte einbetten: `f"Hallo {name}!"`.
|
||||
5. **Format-Spezifizierer beherrschen:** Zahlen präzise runden und formatieren (`{preis:.2f} €`, `{bmi:.1f}`, `{zahl:04d}`).
|
||||
6. **`print()` Parameter steuern:** `sep="-"` (Trennzeichen) und `end=""` (Zeilenende) anwenden.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Theorie & Wichtige Konzepte
|
||||
|
||||
### 1. Tastatureingabe mit `input()`
|
||||
|
||||
Die Funktion `input()` pausiert dein Programm und wartet darauf, dass die Benutzerin etwas im Terminal eintippt und mit <kbd>Enter</kbd> bestätigt.
|
||||
|
||||
```python
|
||||
name = input("Wie heißt du? ")
|
||||
print(f"Schön, dich kennenzulernen, {name}!")
|
||||
```
|
||||
|
||||
> ⚠️ **Achtung, Falle!** `input()` liefert IMMER einen `str`:
|
||||
> ```python
|
||||
> alter_text = input("Dein Alter: ") # Wenn du 15 eingibst, ist der Wert "15" (Text)!
|
||||
> # alter_text + 1 💥 TypeError: can only concatenate str (not "int") to str
|
||||
> ```
|
||||
|
||||
### 2. Typumwandlung (Type Casting)
|
||||
|
||||
Um mit Eingabezahlen rechnen zu können, musst du sie in `int` (Ganzzahl) oder `float` (Kommazahl) umwandeln:
|
||||
|
||||
```python
|
||||
# Ganze Zahl einlesen:
|
||||
alter = int(input("Dein Alter in Jahren: "))
|
||||
tage = alter * 365
|
||||
|
||||
# Kommazahl einlesen:
|
||||
preis = float(input("Preis in Euro (z.B. 4.99): "))
|
||||
rabatt = preis * 0.9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Moderne f-Strings (Formatierte Strings)
|
||||
|
||||
Seit Python 3.6 nutzt man **f-Strings** (ein vorangestelltes `f` vor den Anführungszeichen). Alles innerhalb geschweifter Klammern `{...}` wird direkt als Python-Code ausgewertet:
|
||||
|
||||
```python
|
||||
name = "Mia"
|
||||
punkte = 42
|
||||
print(f"Spielerin {name} hat {punkte} Punkte (doppelt so viel: {punkte * 2})!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Formatierungs-Cheat-Sheet in f-Strings
|
||||
|
||||
Hinter einem Doppelpunkt `:` in den geschweiften Klammern kannst du das Format exakt bestimmen:
|
||||
|
||||
| Format-Code | Bedeutung | Beispiel | Ergebnis |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `{x:.2f}` | Kommazahl mit genau 2 Dezimalstellen | `{12.5:.2f} €` | `"12.50 €"` |
|
||||
| `{x:.1f}` | Kommazahl mit genau 1 Dezimalstelle | `{23.148:.1f}` | `"23.1"` |
|
||||
| `{x:.1%}` | Prozentangabe (multipliziert mit 100) | `{0.19:.1%}` | `"19.0%"` |
|
||||
| `{n:04d}` | Ganzzahl mit führenden Nullen (4 Stellen) | `{7:04d}` | `"0007"` |
|
||||
| `{s:>10}` | Text rechtsbündig (Breite 10) | `{"Python":>10}` | `" Python"` |
|
||||
|
||||
---
|
||||
|
||||
### 5. `print()` Parameter: `sep` und `end`
|
||||
|
||||
Die `print()`-Funktion hat zwei sehr praktische optionale Parameter:
|
||||
- `sep`: Trennzeichen zwischen mehreren Werten (Standard: ein Leerzeichen `" "`).
|
||||
- `end`: Zeichen am Ende der Ausgabe (Standard: Zeilenumbruch `"\n"`).
|
||||
|
||||
```python
|
||||
# sep: Eigenes Trennzeichen
|
||||
print("2026", "08", "29", sep="-")
|
||||
# Ausgabe: 2026-08-29
|
||||
|
||||
# end: Kein Zeilenumbruch, nächste Ausgabe bleibt in derselben Zeile
|
||||
print("Lade Fortschritt", end="... ")
|
||||
print("100% Fertig!")
|
||||
# Ausgabe: Lade Fortschritt... 100% Fertig!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `g03_ein_und_ausgabe/aufgabe.py` und implementiere die 4 Funktionen:
|
||||
|
||||
1. **TODO 1:** `begruessungs_text(name: str, stadt: str) -> str`
|
||||
- Rückgabe: `f"Hallo {name}, herzlich willkommen in {stadt}!"`
|
||||
2. **TODO 2:** `berechne_alter_in_tagen(jahre: int) -> int`
|
||||
- Multipliziere `jahre * 365`.
|
||||
3. **TODO 3:** `formatiere_rechnungsposten(artikel: str, anzahl: int, einzelpreis: float) -> str`
|
||||
- Berechne Gesamtpreis und formatiere: `f"{anzahl}x {artikel} à {einzelpreis:.2f} € = {gesamt:.2f} €"`
|
||||
4. **TODO 4:** `steckbrief(name: str, groesse_m: float, gewicht_kg: float) -> str`
|
||||
- Berechne BMI: `gewicht_kg / (groesse_m ** 2)`
|
||||
- Formatiere: `f"Steckbrief: {name} | Größe: {groesse_m:.2f} m | Gewicht: {gewicht_kg:.1f} kg | BMI: {bmi:.1f}"`
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Tests ausführen
|
||||
|
||||
Überprüfe deine Lösung im Terminal mit:
|
||||
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
|
||||
Wenn alle 4 Tests mit **`OK`** durchlaufen, hast du das Kapitel gemeistert! 🎉
|
||||
151
g03_ein_und_ausgabe/aufgabe.py
Normal file
151
g03_ein_und_ausgabe/aufgabe.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
"""
|
||||
Kapitel G03: Interaktive Ein- & Ausgabe (Schulabgleich 07.0)
|
||||
============================================================
|
||||
|
||||
In diesem Kapitel lernst du:
|
||||
1. Wie du Benutzereingaben über die Tastatur mit input() entgegennimmst.
|
||||
2. Wie du Datentypen umwandelst (int(input(...)), float(input(...))).
|
||||
3. Wie du moderne f-Strings für formatierte Textausgaben einsetzt.
|
||||
4. Wie du Zahlenwerte formatiert darstellst ({preis:.2f} €, {prozent:.1%}, {zahl:04d}).
|
||||
5. Wie du print() mit den Parametern sep= und end= steuerst.
|
||||
|
||||
Bearbeite die Aufgaben TODO 1 bis TODO 4.
|
||||
Führe danach die Tests aus mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Begrüßungstext mit f-String
|
||||
#
|
||||
# Schreibe eine Funktion 'begruessungs_text(name: str, stadt: str) -> str'.
|
||||
# Sie soll folgenden Text zurückgeben:
|
||||
# "Hallo {name}, herzlich willkommen in {stadt}!"
|
||||
#
|
||||
# Beispiel:
|
||||
# begruessungs_text("Anna", "Wien") -> "Hallo Anna, herzlich willkommen in Wien!"
|
||||
# ==============================================================================
|
||||
|
||||
def begruessungs_text(name: str, stadt: str) -> str:
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Alter in Tagen berechnen
|
||||
#
|
||||
# Schreibe eine Funktion 'berechne_alter_in_tagen(jahre: int) -> int'.
|
||||
# Sie erhält das Alter in ganzen Jahren (z.B. 18) und soll das Alter in Tagen
|
||||
# berechnen (wir rechnen vereinfacht mit genau 365 Tagen pro Jahr).
|
||||
#
|
||||
# Beispiel:
|
||||
# berechne_alter_in_tagen(18) -> 6570
|
||||
# berechne_alter_in_tagen(1) -> 365
|
||||
# ==============================================================================
|
||||
|
||||
def berechne_alter_in_tagen(jahre: int) -> int:
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Rechnungsposten formatieren
|
||||
#
|
||||
# Schreibe eine Funktion 'formatiere_rechnungsposten(artikel: str, anzahl: int, einzelpreis: float) -> str'.
|
||||
# Sie berechnet den Gesamtpreis (anzahl * einzelpreis) und gibt einen formatierten
|
||||
# Rechnungs-String zurück.
|
||||
#
|
||||
# Format:
|
||||
# "{anzahl}x {artikel} à {einzelpreis:.2f} € = {gesamtpreis:.2f} €"
|
||||
#
|
||||
# WICHTIG: Die Preise müssen immer auf genau 2 Nachkommastellen formatiert sein!
|
||||
#
|
||||
# Beispiele:
|
||||
# formatiere_rechnungsposten("Kaffee", 3, 2.5) -> "3x Kaffee à 2.50 € = 7.50 €"
|
||||
# formatiere_rechnungsposten("Buch", 1, 19.99) -> "1x Buch à 19.99 € = 19.99 €"
|
||||
# formatiere_rechnungsposten("Semmel", 5, 0.40) -> "5x Semmel à 0.40 € = 2.00 €"
|
||||
# ==============================================================================
|
||||
|
||||
def formatiere_rechnungsposten(artikel: str, anzahl: int, einzelpreis: float) -> str:
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Steckbrief mit BMI-Berechnung
|
||||
#
|
||||
# Schreibe eine Funktion 'steckbrief(name: str, groesse_m: float, gewicht_kg: float) -> str'.
|
||||
# 1. Berechne den BMI (Body-Mass-Index) nach der Formel:
|
||||
# bmi = gewicht_kg / (groesse_m ** 2)
|
||||
# 2. Gib folgenden formatierten Steckbrief-String zurück:
|
||||
# "Steckbrief: {name} | Größe: {groesse_m:.2f} m | Gewicht: {gewicht_kg:.1f} kg | BMI: {bmi:.1f}"
|
||||
#
|
||||
# WICHTIG:
|
||||
# - Größe auf 2 Nachkommastellen formatiert ({groesse_m:.2f} m)
|
||||
# - Gewicht auf 1 Nachkommastelle formatiert ({gewicht_kg:.1f} kg)
|
||||
# - BMI auf 1 Nachkommastelle formatiert ({bmi:.1f})
|
||||
#
|
||||
# Beispiel:
|
||||
# steckbrief("Alex", 1.80, 75.0) -> "Steckbrief: Alex | Größe: 1.80 m | Gewicht: 75.0 kg | BMI: 23.1"
|
||||
# steckbrief("Mia", 1.65, 58.5) -> "Steckbrief: Mia | Größe: 1.65 m | Gewicht: 58.5 kg | BMI: 21.5"
|
||||
# ==============================================================================
|
||||
|
||||
def steckbrief(name: str, groesse_m: float, gewicht_kg: float) -> str:
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Interaktives Hauptprogramm zum Ausprobieren:
|
||||
# (Führe dieses Skript aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("💬 INTERAKTIVE EIN- & AUSGABE DEMO")
|
||||
print("=" * 60)
|
||||
|
||||
# 1. Demonstration von print() mit sep und end
|
||||
print("Python", "ist", "klasse!", sep=" - ")
|
||||
print("Lade Daten", end="... ")
|
||||
print("Fertig!\n")
|
||||
|
||||
# 2. Interaktiver Dialog mit Tastatureingabe
|
||||
try:
|
||||
benutzer_name = input("Wie heißt du? ")
|
||||
benutzer_stadt = input("Aus welcher Stadt kommst du? ")
|
||||
begruessung = begruessungs_text(benutzer_name, benutzer_stadt)
|
||||
if begruessung:
|
||||
print(begruessung)
|
||||
else:
|
||||
print(f"Hallo {benutzer_name} aus {benutzer_stadt} (Implementiere TODO 1)!")
|
||||
|
||||
alter_str = input("\nWie alt bist du (in Jahren)? ")
|
||||
# Achtung: input() liefert immer einen String -> Umwandlung mit int() nötig!
|
||||
alter_int = int(alter_str)
|
||||
tage = berechne_alter_in_tagen(alter_int)
|
||||
if tage is not None:
|
||||
print(f"Wahnsinn, du lebst schon seit ca. {tage} Tagen!")
|
||||
else:
|
||||
print("Implementiere TODO 2 für die Tage-Berechnung!")
|
||||
|
||||
print("\n--- Kassenbon-Generator ---")
|
||||
art = input("Welcher Artikel? ")
|
||||
anz = int(input("Wie viele Stück? "))
|
||||
preis = float(input("Einzelpreis in € (z.B. 2.99): "))
|
||||
posten = formatiere_rechnungsposten(art, anz, preis)
|
||||
if posten:
|
||||
print(posten)
|
||||
else:
|
||||
print("Implementiere TODO 3 für den formatierten Rechnungsposten!")
|
||||
|
||||
print("\n--- Steckbrief & BMI-Rechner ---")
|
||||
gr = float(input("Deine Körpergröße in Metern (z.B. 1.75): "))
|
||||
gw = float(input("Dein Körpergewicht in kg (z.B. 68.0): "))
|
||||
sb = steckbrief(benutzer_name, gr, gw)
|
||||
if sb:
|
||||
print(sb)
|
||||
else:
|
||||
print("Implementiere TODO 4 für den Steckbrief!")
|
||||
|
||||
except (ValueError, TypeError) as fehler:
|
||||
print(f"\n💡 Hinweis / Fehleingabe: {fehler}")
|
||||
print("Achte darauf, bei Zahlen nur Ziffern und bei Kommazahlen einen Punkt '.' einzugeben!")
|
||||
259
g03_ein_und_ausgabe/index.html
Normal file
259
g03_ein_und_ausgabe/index.html
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G03: Interaktive Ein- & Ausgabe</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g02_variablen_und_datentypen/index.html">← Kapitel G02</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G03</span>
|
||||
<span>›</span>
|
||||
<a href="../g04_verzweigungen_und_bedingungen/index.html">Kapitel G04 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G03 • Schulabgleich 07.0</div>
|
||||
<h1>Interaktive Ein- & Ausgabe 💬⌨️</h1>
|
||||
<p>Lerne, wie du Benutzereingaben mit <code>input()</code> verarbeitest, Typen umwandelst und Daten mit modernen f-Strings elegant formatierst.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie & Einführung -->
|
||||
<section class="card">
|
||||
<h2>1. Die Dialog-Analogie: Wenn Programme sprechen lernen 🗣️</h2>
|
||||
|
||||
<p>
|
||||
Bisher haben unsere Programme Werte starr im Code festgelegt. In der echten Welt müssen Programme jedoch auf Eingaben von Nutzerinnen und Nutzern reagieren: Ein Chatbot, ein Online-Shop-Kassenbon oder ein Videospiel-Menü.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🎭 Die Dialog-Analogie (Das Interview):</div>
|
||||
Stell dir dein Programm wie eine Interviewerin vor:
|
||||
<br>1. <strong>Frage stellen:</strong> Das Programm fragt höflich nach Informationen (<code>input("Name: ")</code>).
|
||||
<br>2. <strong>Zuhören & Notieren:</strong> Das Programm nimmt die Antwort entgegen (immer als Text!).
|
||||
<br>3. <strong>Verarbeiten:</strong> Das Programm wandelt Zahlen um und rechnet damit.
|
||||
<br>4. <strong>Antworten:</strong> Das Programm gibt das schön formatierte Ergebnis zurück (<code>print(...)</code> mit f-String).
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. input() & Typumwandlung -->
|
||||
<section class="card">
|
||||
<h2>2. Tastatureingabe mit <code>input()</code> & Typumwandlung ⚠️</h2>
|
||||
|
||||
<p>
|
||||
Mit der eingebauten Funktion <code>input()</code> pausiert Python die Programmausführung und wartet auf Tastatureingaben im Terminal.
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python Eingabe</span>
|
||||
</div>
|
||||
<pre><span class="var">name</span> = <span class="fn">input</span>(<span class="str">"Wie lautet dein Name? "</span>)
|
||||
<span class="fn">print</span>(<span class="str">f"Hallo {name}!"</span>)</pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-danger">
|
||||
<div class="box-title">🚨 Die goldene Regel: input() liefert IMMER einen String (str)!</div>
|
||||
Selbst wenn die Benutzerin <code>42</code> eintippt, speichert Python den Text <code>"42"</code>.
|
||||
<br>Wenn du versuchst, <code>"42" + 5</code> zu rechnen, stürzt Python mit einem <code>TypeError</code> ab!
|
||||
</div>
|
||||
|
||||
<h3>Typkonvertierung (Type Casting):</h3>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Ganze Zahlen und Kommazahlen umwandeln</span></div>
|
||||
<pre><span class="cm"># 1. Ganze Zahl (int):</span>
|
||||
<span class="var">alter_text</span> = <span class="fn">input</span>(<span class="str">"Dein Alter: "</span>) <span class="cm"># z.B. "18"</span>
|
||||
<span class="var">alter</span> = <span class="fn">int</span>(<span class="var">alter_text</span>) <span class="cm"># Jetzt als Ganzzahl 18</span>
|
||||
<span class="var">tage</span> = <span class="var">alter</span> * <span class="num">365</span> <span class="cm"># Rechnen klappt problemlos!</span>
|
||||
|
||||
<span class="cm"># Direkt in einer Zeile kombiniert:</span>
|
||||
<span class="var">alter</span> = <span class="fn">int</span>(<span class="fn">input</span>(<span class="str">"Dein Alter: "</span>))
|
||||
|
||||
<span class="cm"># 2. Kommazahl (float):</span>
|
||||
<span class="var">preis</span> = <span class="fn">float</span>(<span class="fn">input</span>(<span class="str">"Preis in Euro (z.B. 4.99): "</span>))
|
||||
<span class="var">brutto</span> = <span class="var">preis</span> * <span class="num">1.20</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. f-Strings & Cheat-Sheet -->
|
||||
<section class="card">
|
||||
<h2>3. Moderne f-Strings & Formatierungs-Cheat-Sheet 📄</h2>
|
||||
|
||||
<p>
|
||||
In modernem Python (ab Version 3.6) sind <strong>f-Strings</strong> (Formatted String Literals) der absolute Standard. Setze ein <code>f</code> direkt vor die Anführungszeichen, und du kannst Variablen und Ausdrücke direkt in <code>{...}</code> einbetten.
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Beispiel: Ausdrücke direkt im f-String berechnen</span></div>
|
||||
<pre><span class="var">name</span> = <span class="str">"Mia"</span>
|
||||
<span class="var">alter</span> = <span class="num">16</span>
|
||||
<span class="fn">print</span>(<span class="str">f"Hallo {name}, nächstes Jahr bist du schon {alter + 1} Jahre alt!"</span>)</pre>
|
||||
</div>
|
||||
|
||||
<h3>Format-Spezifizierer (Format Codes):</h3>
|
||||
<p>Hinter einem Doppelpunkt <code>:</code> kannst du das Aussehen von Zahlen exakt steuern:</p>
|
||||
|
||||
<div style="overflow-x: auto; margin: 15px 0;">
|
||||
<table style="width: 100%; border-collapse: collapse; text-align: left; background: white; border-radius: 8px; overflow: hidden; box-shadow: var(--shadow-sm);">
|
||||
<thead>
|
||||
<tr style="background: var(--primary); color: white;">
|
||||
<th style="padding: 12px 14px;">Code</th>
|
||||
<th style="padding: 12px 14px;">Bedeutung</th>
|
||||
<th style="padding: 12px 14px;">Beispiel</th>
|
||||
<th style="padding: 12px 14px;">Ergebnis</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 14px;"><code>{x:.2f}</code></td>
|
||||
<td style="padding: 10px 14px;">Genau 2 Nachkommastellen (z.B. für Geldbeträge)</td>
|
||||
<td style="padding: 10px 14px;"><code>f"{2.5:.2f} €"</code></td>
|
||||
<td style="padding: 10px 14px;"><strong style="color: var(--primary);">"2.50 €"</strong></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 14px;"><code>{x:.1f}</code></td>
|
||||
<td style="padding: 10px 14px;">Genau 1 Nachkommastelle (z.B. für BMI / Notenschnitt)</td>
|
||||
<td style="padding: 10px 14px;"><code>f"{23.148:.1f}"</code></td>
|
||||
<td style="padding: 10px 14px;"><strong style="color: var(--primary);">"23.1"</strong></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 14px;"><code>{x:.1%}</code></td>
|
||||
<td style="padding: 10px 14px;">Prozentwert (multipliziert automatisch mit 100)</td>
|
||||
<td style="padding: 10px 14px;"><code>f"{0.19:.1%}"</code></td>
|
||||
<td style="padding: 10px 14px;"><strong style="color: var(--primary);">"19.0%"</strong></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 14px;"><code>{n:04d}</code></td>
|
||||
<td style="padding: 10px 14px;">Ganzzahl mit führenden Nullen (mind. 4 Ziffern)</td>
|
||||
<td style="padding: 10px 14px;"><code>f"{7:04d}"</code></td>
|
||||
<td style="padding: 10px 14px;"><strong style="color: var(--primary);">"0007"</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px 14px;"><code>{s:>10}</code></td>
|
||||
<td style="padding: 10px 14px;">Rechtsbündig in einer 10-Zeichen-Spalte</td>
|
||||
<td style="padding: 10px 14px;"><code>f'{"Kaffee":>10}'</code></td>
|
||||
<td style="padding: 10px 14px;"><strong style="color: var(--primary);">" Kaffee"</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>4. <code>print()</code> mit Parametern steuern (<code>sep</code> & <code>end</code>)</h3>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>sep und end Parameter</span></div>
|
||||
<pre><span class="cm"># sep ändert das Trennzeichen zwischen Argumenten:</span>
|
||||
<span class="fn">print</span>(<span class="str">"2026"</span>, <span class="str">"08"</span>, <span class="str">"29"</span>, <span class="var">sep</span>=<span class="str">"-"</span>)
|
||||
<span class="cm"># Ausgabe: 2026-08-29</span>
|
||||
|
||||
<span class="cm"># end verhindert den Zeilenumbruch:</span>
|
||||
<span class="fn">print</span>(<span class="str">"Lade Daten"</span>, <span class="var">end</span>=<span class="str">"... "</span>)
|
||||
<span class="fn">print</span>(<span class="str">"Fertig!"</span>)
|
||||
<span class="cm"># Ausgabe: Lade Daten... Fertig!</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Deine Aufgaben -->
|
||||
<section class="card">
|
||||
<h2>4. 📝 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g03_ein_und_ausgabe/aufgabe.py</code> und setze folgende 4 Funktionen um:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>begruessungs_text(name, stadt)</code></strong><br>
|
||||
Erstelle den String: <code>f"Hallo {name}, herzlich willkommen in {stadt}!"</code>
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>berechne_alter_in_tagen(jahre)</code></strong><br>
|
||||
Multipliziere das übergebene Alter in Jahren mit <code>365</code> und gib das Ergebnis als <code>int</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>formatiere_rechnungsposten(artikel, anzahl, einzelpreis)</code></strong><br>
|
||||
Berechne den Gesamtpreis (<code>anzahl * einzelpreis</code>) und formatiere beide Preise mit genau 2 Nachkommastellen:<br>
|
||||
<code>f"{anzahl}x {artikel} à {einzelpreis:.2f} € = {gesamtpreis:.2f} €"</code>
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>steckbrief(name, groesse_m, gewicht_kg)</code></strong><br>
|
||||
Berechne den BMI (<code>gewicht_kg / (groesse_m ** 2)</code>) und gib den formatierten Steckbrief zurück:<br>
|
||||
<code>f"Steckbrief: {name} | Größe: {groesse_m:.2f} m | Gewicht: {gewicht_kg:.1f} kg | BMI: {bmi:.1f}"</code>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Rechnungsposten)</summary>
|
||||
<div class="details-content">
|
||||
<p>Multipliziere zuerst <code>gesamtpreis = anzahl * einzelpreis</code>. Setze dann beide Werte in den f-String ein und formatiere sie mit <code>:.2f</code>:</p>
|
||||
<div class="code-container">
|
||||
<pre><code>gesamtpreis = anzahl * einzelpreis
|
||||
return f"{anzahl}x {artikel} à {einzelpreis:.2f} € = {gesamtpreis:.2f} €"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 4 (BMI & Potenzen in Python)</summary>
|
||||
<div class="details-content">
|
||||
<p>In Python rechnet man Potenzen mit dem Doppelstern-Operator <code>**</code>:</p>
|
||||
<div class="code-container">
|
||||
<pre><code>bmi = gewicht_kg / (groesse_m ** 2)
|
||||
return f"Steckbrief: {name} | Größe: {groesse_m:.2f} m | Gewicht: {gewicht_kg:.1f} kg | BMI: {bmi:.1f}"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 5. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. 🧪 Automatische Tests & Überprüfung</h2>
|
||||
<p>Führe das Testskript im Terminal aus, um deine Funktionen zu prüfen:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<p>Um das interaktive Programm mit echten Tastatureingaben auszuprobieren, führe aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Interaktiver Test</span></div>
|
||||
<pre><code>python3 aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g02_variablen_und_datentypen/index.html" class="btn btn-secondary">← Zurück zu Kapitel G02</a>
|
||||
<a href="../g04_verzweigungen_und_bedingungen/index.html" class="btn">Weiter zu Kapitel G04: Verzweigungen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
58
g03_ein_und_ausgabe/musterloesung.py
Normal file
58
g03_ein_und_ausgabe/musterloesung.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
"""
|
||||
Kapitel G03: Interaktive Ein- & Ausgabe (Schulabgleich 07.0)
|
||||
============================================================
|
||||
Musterlösung mit sauberen f-Strings, Typkonvertierungen und Formatangaben.
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Begrüßungstext mit f-String
|
||||
# ==============================================================================
|
||||
def begruessungs_text(name: str, stadt: str) -> str:
|
||||
"""Gibt einen freundlichen Begrüßungstext mit f-String zurück."""
|
||||
return f"Hallo {name}, herzlich willkommen in {stadt}!"
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Alter in Tagen berechnen
|
||||
# ==============================================================================
|
||||
def berechne_alter_in_tagen(jahre: int) -> int:
|
||||
"""Berechnet das ungefähre Alter in Tagen (365 Tage pro Jahr)."""
|
||||
return jahre * 365
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Rechnungsposten formatieren
|
||||
# ==============================================================================
|
||||
def formatiere_rechnungsposten(artikel: str, anzahl: int, einzelpreis: float) -> str:
|
||||
"""Formatiert einen Rechnungsposten mit 2 Nachkommastellen für Preise."""
|
||||
gesamtpreis = anzahl * einzelpreis
|
||||
return f"{anzahl}x {artikel} à {einzelpreis:.2f} € = {gesamtpreis:.2f} €"
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Steckbrief mit BMI-Berechnung
|
||||
# ==============================================================================
|
||||
def steckbrief(name: str, groesse_m: float, gewicht_kg: float) -> str:
|
||||
"""Berechnet den BMI und gibt einen formatierten Steckbrief zurück."""
|
||||
bmi = gewicht_kg / (groesse_m ** 2)
|
||||
return f"Steckbrief: {name} | Größe: {groesse_m:.2f} m | Gewicht: {gewicht_kg:.1f} kg | BMI: {bmi:.1f}"
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Interaktives Hauptprogramm
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("💬 INTERAKTIVE EIN- & AUSGABE (MUSTERLÖSUNG)")
|
||||
print("=" * 60)
|
||||
|
||||
# 1. Demonstration von print() Parametern:
|
||||
print("Python", "ist", "klasse!", sep=" - ")
|
||||
print("Lade Daten", end="... ")
|
||||
print("Fertig!\n")
|
||||
|
||||
# 2. Demonstration der Funktionen:
|
||||
print(begruessungs_text("Anna", "Wien"))
|
||||
print(f"18 Jahre entsprechen ca. {berechne_alter_in_tagen(18)} Tagen.")
|
||||
print(formatiere_rechnungsposten("Kaffee", 3, 2.5))
|
||||
print(steckbrief("Alex", 1.80, 75.0))
|
||||
145
g03_ein_und_ausgabe/test_aufgabe.py
Normal file
145
g03_ein_und_ausgabe/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import unittest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import importlib.util
|
||||
|
||||
# Pfad zum aktuellen Kapitelverzeichnis
|
||||
CHAPTER_DIR = Path(__file__).parent
|
||||
|
||||
|
||||
def lade_modul(modul_name="aufgabe"):
|
||||
"""Lädt das Modul (aufgabe oder musterloesung) isoliert aus dem Kapitelverzeichnis."""
|
||||
dateipfad = CHAPTER_DIR / f"{modul_name}.py"
|
||||
if not dateipfad.exists():
|
||||
raise FileNotFoundError(f"Datei '{dateipfad}' wurde nicht gefunden.")
|
||||
spec = importlib.util.spec_from_file_location(f"g03_{modul_name}", dateipfad)
|
||||
modul = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(modul)
|
||||
return modul
|
||||
|
||||
|
||||
class TestKapitelG03(unittest.TestCase):
|
||||
"""
|
||||
Testsuite für Kapitel G03: Interaktive Ein- & Ausgabe
|
||||
Überprüft f-String-Formatierungen, Berechnungen und Typkonvertierungen.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.target_modul = getattr(cls, "modul_name", "aufgabe")
|
||||
try:
|
||||
cls.mod = lade_modul(cls.target_modul)
|
||||
except SyntaxError as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"SyntaxError in '{cls.target_modul}.py': {e}"
|
||||
except Exception as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"Fehler beim Laden von '{cls.target_modul}.py': {e}"
|
||||
|
||||
def _get_modul(self):
|
||||
if getattr(self, "mod", None) is None:
|
||||
err = getattr(self, "import_error", f"{self.target_modul}.py konnte nicht geladen werden")
|
||||
self.fail(f"❌ {err}")
|
||||
return self.mod
|
||||
|
||||
def test_01_begruessungs_text(self):
|
||||
"""Prüft TODO 1: begruessungs_text(name, stadt)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "begruessungs_text"),
|
||||
"Fehler: Funktion 'begruessungs_text' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
ergebnis1 = mod.begruessungs_text("Anna", "Wien")
|
||||
erwartet1 = "Hallo Anna, herzlich willkommen in Wien!"
|
||||
self.assertEqual(
|
||||
ergebnis1,
|
||||
erwartet1,
|
||||
f"\n❌ Falsche Begrüßung!\nErwartet: '{erwartet1}'\nErhalten: '{ergebnis1}'"
|
||||
)
|
||||
|
||||
ergebnis2 = mod.begruessungs_text("Maximilian", "München")
|
||||
erwartet2 = "Hallo Maximilian, herzlich willkommen in München!"
|
||||
self.assertEqual(
|
||||
ergebnis2,
|
||||
erwartet2,
|
||||
f"\n❌ Falsche Begrüßung!\nErwartet: '{erwartet2}'\nErhalten: '{ergebnis2}'"
|
||||
)
|
||||
|
||||
def test_02_berechne_alter_in_tagen(self):
|
||||
"""Prüft TODO 2: berechne_alter_in_tagen(jahre)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "berechne_alter_in_tagen"),
|
||||
"Fehler: Funktion 'berechne_alter_in_tagen' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
self.assertEqual(mod.berechne_alter_in_tagen(18), 6570, "18 Jahre * 365 sollte 6570 Tage ergeben!")
|
||||
self.assertEqual(mod.berechne_alter_in_tagen(1), 365, "1 Jahr * 365 sollte 365 Tage ergeben!")
|
||||
self.assertEqual(mod.berechne_alter_in_tagen(0), 0, "0 Jahre * 365 sollte 0 Tage ergeben!")
|
||||
self.assertEqual(mod.berechne_alter_in_tagen(25), 9125, "25 Jahre * 365 sollte 9125 Tage ergeben!")
|
||||
|
||||
def test_03_formatiere_rechnungsposten(self):
|
||||
"""Prüft TODO 3: formatiere_rechnungsposten(artikel, anzahl, einzelpreis)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "formatiere_rechnungsposten"),
|
||||
"Fehler: Funktion 'formatiere_rechnungsposten' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# Test 1: Kaffee
|
||||
erg1 = mod.formatiere_rechnungsposten("Kaffee", 3, 2.5)
|
||||
erw1 = "3x Kaffee à 2.50 € = 7.50 €"
|
||||
self.assertEqual(
|
||||
erg1,
|
||||
erw1,
|
||||
f"\n❌ Formatierungsfehler bei Rechnungsposten!\nErwartet: '{erw1}'\nErhalten: '{erg1}'\n💡 Tipp: Achte auf ':.2f' für zwei Nachkommastellen bei beiden Preisen!"
|
||||
)
|
||||
|
||||
# Test 2: Buch
|
||||
erg2 = mod.formatiere_rechnungsposten("Buch", 1, 19.99)
|
||||
erw2 = "1x Buch à 19.99 € = 19.99 €"
|
||||
self.assertEqual(
|
||||
erg2,
|
||||
erw2,
|
||||
f"\n❌ Formatierungsfehler bei Rechnungsposten!\nErwartet: '{erw2}'\nErhalten: '{erg2}'"
|
||||
)
|
||||
|
||||
# Test 3: Semmel (Rundung / Nullen am Ende z.B. 0.40 € und 2.00 €)
|
||||
erg3 = mod.formatiere_rechnungsposten("Semmel", 5, 0.4)
|
||||
erw3 = "5x Semmel à 0.40 € = 2.00 €"
|
||||
self.assertEqual(
|
||||
erg3,
|
||||
erw3,
|
||||
f"\n❌ Formatierungsfehler bei Rechnungsposten!\nErwartet: '{erw3}'\nErhalten: '{erg3}'"
|
||||
)
|
||||
|
||||
def test_04_steckbrief_und_bmi(self):
|
||||
"""Prüft TODO 4: steckbrief(name, groesse_m, gewicht_kg)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "steckbrief"),
|
||||
"Fehler: Funktion 'steckbrief' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# Test 1: Alex (75 kg / (1.80^2) = 23.1481... -> 23.1)
|
||||
erg1 = mod.steckbrief("Alex", 1.80, 75.0)
|
||||
erw1 = "Steckbrief: Alex | Größe: 1.80 m | Gewicht: 75.0 kg | BMI: 23.1"
|
||||
self.assertEqual(
|
||||
erg1,
|
||||
erw1,
|
||||
f"\n❌ Formatierungsfehler im Steckbrief!\nErwartet: '{erw1}'\nErhalten: '{erg1}'\n💡 Formel: BMI = gewicht / (groesse ** 2) mit ':.1f'"
|
||||
)
|
||||
|
||||
# Test 2: Mia (58.5 kg / (1.65^2) = 21.4876... -> 21.5)
|
||||
erg2 = mod.steckbrief("Mia", 1.65, 58.5)
|
||||
erw2 = "Steckbrief: Mia | Größe: 1.65 m | Gewicht: 58.5 kg | BMI: 21.5"
|
||||
self.assertEqual(
|
||||
erg2,
|
||||
erw2,
|
||||
f"\n❌ Formatierungsfehler im Steckbrief!\nErwartet: '{erw2}'\nErhalten: '{erg2}'"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
129
g04_verzweigungen_und_bedingungen/README.md
Normal file
129
g04_verzweigungen_und_bedingungen/README.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# Kapitel G04: Verzweigungen & Bedingungen (Schulabgleich 08.0) 🛤️🔀
|
||||
|
||||
Herzlich willkommen zum Kapitel **Bedingungen und Verzweigungen**!
|
||||
|
||||
Programme müssen oft Entscheidungen treffen: *Darf die Person schon Auto fahren?*, *Bekommt sie einen Rabatt?*, *Ist heute ein Schaltjahr?*. In Python steuern wir solche Entscheidungen mit `if`, `elif` und `else`.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Lernziele
|
||||
|
||||
1. **Entscheidungsstrukturen verstehen:** `if`, `elif` und `else` für logische Programmabläufe einsetzen.
|
||||
2. **Die Eisenbahn-Weichen-Analogie begreifen:** Sobald die erste Bedingung zutrifft, werden alle nachfolgenden `elif`/`else`-Zweige übersprungen.
|
||||
3. **Vergleichsoperatoren beherrschen:** `==`, `!=`, `<`, `>`, `<=`, `>=`.
|
||||
4. **Logische Operatoren kombinieren:** `and` (und), `or` (oder), `not` (nicht / Verneinung).
|
||||
5. **Klammern & Rangfolge anwenden:** Komplexe Bedingungen mit `()` sicher strukturieren.
|
||||
6. **Flache vs. tief verschachtelte Bedingungen:** Sauberen, lesbaren Code nach dem KISS-Prinzip schreiben.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Theorie & Wichtige Konzepte
|
||||
|
||||
### 1. Die Weichen-Analogie (Eisenbahn-Gleis) 🛤️
|
||||
|
||||
Stell dir dein Programm wie einen Zug auf den Schienen vor. An einer Weiche entscheidet das Signal (`Bedingung`), auf welches Gleis der Zug abbiegt:
|
||||
|
||||
```python
|
||||
if alter < 12:
|
||||
preis = 6.0 # Gleis 1 (Kind)
|
||||
elif alter >= 65:
|
||||
preis = 8.5 # Gleis 2 (Senior)
|
||||
elif ist_student:
|
||||
preis = 9.5 # Gleis 3 (Student)
|
||||
else:
|
||||
preis = 12.0 # Ausweichgleis (Standard-Erwachsener)
|
||||
```
|
||||
|
||||
> 🔑 **Wichtig:** Python prüft die Bedingungen von oben nach unten. Der **erste** Block, dessen Bedingung `True` ergibt, wird ausgeführt. Danach verlässt Python die gesamte Weiche!
|
||||
|
||||
---
|
||||
|
||||
### 2. Die Vergleichsoperatoren
|
||||
|
||||
| Operator | Bedeutung | Beispiel | Ergebnis |
|
||||
| :---: | :--- | :--- | :--- |
|
||||
| `==` | Ist gleich? *(Vorsicht: Nicht mit Zuweisung `=` verwechseln!)* | `5 == 5` | `True` |
|
||||
| `!=` | Ist ungleich? | `5 != 3` | `True` |
|
||||
| `<` | Kleiner als | `10 < 20` | `True` |
|
||||
| `>` | Größer als | `10 > 20` | `False` |
|
||||
| `<=` | Kleiner oder gleich (Grenzwert inkludiert) | `10 <= 10` | `True` |
|
||||
| `>=` | Größer oder gleich (Grenzwert inkludiert) | `18 >= 18` | `True` |
|
||||
|
||||
---
|
||||
|
||||
### 3. Logische Operatoren & Wahrheitstabellen
|
||||
|
||||
Oft reicht eine einzelne Bedingung nicht aus. Mit logischen Operatoren verknüpfst du mehrere Bedingungen:
|
||||
|
||||
#### `and` (Logisches UND – Beide müssen wahr sein):
|
||||
| Bedingung A | Bedingung B | `A and B` |
|
||||
| :---: | :---: | :---: |
|
||||
| `True` | `True` | **`True`** |
|
||||
| `True` | `False` | `False` |
|
||||
| `False` | `True` | `False` |
|
||||
| `False` | `False` | `False` |
|
||||
|
||||
#### `or` (Logisches ODER – Mindestens eins muss wahr sein):
|
||||
| Bedingung A | Bedingung B | `A or B` |
|
||||
| :---: | :---: | :---: |
|
||||
| `True` | `True` | **`True`** |
|
||||
| `True` | `False` | **`True`** |
|
||||
| `False` | `True` | **`True`** |
|
||||
| `False` | `False` | `False` |
|
||||
|
||||
#### `not` (Logisches NICHT – Dreht den Wahrheitswert um):
|
||||
- `not True` ergibt `False`
|
||||
- `not False` ergibt `True`
|
||||
|
||||
---
|
||||
|
||||
### 4. Das Schaltjahr-Rätsel 📅
|
||||
|
||||
Ein schönes Praxisbeispiel für logische Verknüpfungen ist die gregorianische Schaltjahr-Regel:
|
||||
1. Ein Jahr ist ein Schaltjahr, wenn es durch 4 teilbar ist (`jahr % 4 == 0`).
|
||||
2. Säkularjahre (Jahrhunderte wie 1900, 2100) sind **keine** Schaltjahre (`jahr % 100 != 0`),
|
||||
3. **außer** sie sind durch 400 teilbar (wie 2000, 2400: `jahr % 400 == 0`).
|
||||
|
||||
In Python formuliert:
|
||||
```python
|
||||
ist_schalt = (jahr % 4 == 0 and jahr % 100 != 0) or (jahr % 400 == 0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `g04_verzweigungen_und_bedingungen/aufgabe.py` und implementiere die 4 Funktionen:
|
||||
|
||||
1. **TODO 1: Kinokarten-Preisrechner**
|
||||
- `ticket_preis(alter: int, ist_student: bool) -> float`
|
||||
- Alter < 12: `6.0` €
|
||||
- Alter >= 65: `8.5` €
|
||||
- 12 bis 64 Jahre: Wenn `ist_student` -> `9.5` €, sonst -> `12.0` €
|
||||
|
||||
2. **TODO 2: Schulnoten-Ermittlung**
|
||||
- `schulnote_text(punkte: int) -> str`
|
||||
- `< 0` oder `> 100`: `"Ungültige Punktezahl"`
|
||||
- `>= 90`: `"Sehr gut"`, `>= 75`: `"Gut"`, `>= 60`: `"Befriedigend"`, `>= 50`: `"Genügend"`, `< 50`: `"Nicht genügend"`
|
||||
|
||||
3. **TODO 3: Schaltjahr-Erkennung**
|
||||
- `ist_schaltjahr(jahr: int) -> bool`
|
||||
- `(jahr % 4 == 0 and jahr % 100 != 0) or (jahr % 400 == 0)`
|
||||
|
||||
4. **TODO 4: Achterbahn-Zulassung**
|
||||
- `kann_achterbahn_fahren(groesse_cm: int, begleitung_erwachsen: bool) -> bool`
|
||||
- Ab 140 cm: immer `True`
|
||||
- Ab 120 cm bis 139 cm: `True`, wenn `begleitung_erwachsen == True`, sonst `False`
|
||||
- Unter 120 cm: immer `False`
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Tests ausführen
|
||||
|
||||
Überprüfe deine Lösung im Terminal mit:
|
||||
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
|
||||
Wenn alle 4 Tests mit **`OK`** durchlaufen, hast du das Kapitel gemeistert! 🎉
|
||||
167
g04_verzweigungen_und_bedingungen/aufgabe.py
Normal file
167
g04_verzweigungen_und_bedingungen/aufgabe.py
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
"""
|
||||
Kapitel G04: Verzweigungen & Bedingungen (Schulabgleich 08.0)
|
||||
============================================================
|
||||
|
||||
In diesem Kapitel lernst du:
|
||||
1. Wie du Entscheidungen mit if, elif und else programmierst.
|
||||
2. Vergleichsoperatoren: ==, !=, <, >, <=, >=.
|
||||
3. Logische Operatoren: and, or, not.
|
||||
4. Flache elif-Ketten vs. tief verschachtelte Bedingungen.
|
||||
5. Wie du komplexe Geschäftslogik und Grenzwerte sauber implementierst.
|
||||
|
||||
Bearbeite die Aufgaben TODO 1 bis TODO 4.
|
||||
Führe danach die Tests aus mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Kinokarten-Preisrechner
|
||||
#
|
||||
# Schreibe eine Funktion 'ticket_preis(alter: int, ist_student: bool) -> float'.
|
||||
# Sie berechnet den Ticketpreis nach folgenden Tarif-Regeln:
|
||||
# - Kinder unter 12 Jahren (alter < 12): 6.00 € (Kindertarif)
|
||||
# - Senioren ab 65 Jahren (alter >= 65): 8.50 € (Seniorentarif)
|
||||
# - Alle anderen Personen (12 bis 64 Jahre):
|
||||
# - Wenn ist_student True ist: 9.50 € (Studenten-/Ermäßigungstarif)
|
||||
# - Wenn ist_student False ist: 12.00 € (Regulärer Erwachsenentarif)
|
||||
#
|
||||
# Beispiele:
|
||||
# ticket_preis(8, False) -> 6.0
|
||||
# ticket_preis(70, False) -> 8.5
|
||||
# ticket_preis(22, True) -> 9.5
|
||||
# ticket_preis(30, False) -> 12.0
|
||||
# ==============================================================================
|
||||
|
||||
def ticket_preis(alter: int, ist_student: bool) -> float:
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schulnoten-Ermittlung
|
||||
#
|
||||
# Schreibe eine Funktion 'schulnote_text(punkte: int) -> str'.
|
||||
# Sie ordnet einer erreichten Punktezahl (0 bis 100) die passende Textnote zu:
|
||||
# - 90 bis 100 Punkte (punkte >= 90): "Sehr gut"
|
||||
# - 75 bis 89 Punkte (punkte >= 75): "Gut"
|
||||
# - 60 bis 74 Punkte (punkte >= 60): "Befriedigend"
|
||||
# - 50 bis 59 Punkte (punkte >= 50): "Genügend"
|
||||
# - 0 bis 49 Punkte (punkte < 50): "Nicht genügend"
|
||||
# - Werte unter 0 oder über 100: "Ungültige Punktezahl"
|
||||
#
|
||||
# Beispiele:
|
||||
# schulnote_text(95) -> "Sehr gut"
|
||||
# schulnote_text(75) -> "Gut"
|
||||
# schulnote_text(49) -> "Nicht genügend"
|
||||
# schulnote_text(110) -> "Ungültige Punktezahl"
|
||||
# schulnote_text(-5) -> "Ungültige Punktezahl"
|
||||
# ==============================================================================
|
||||
|
||||
def schulnote_text(punkte: int) -> str:
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schaltjahr-Erkennung
|
||||
#
|
||||
# Schreibe eine Funktion 'ist_schaltjahr(jahr: int) -> bool'.
|
||||
# Die Funktion soll prüfen, ob ein übergebenes Kalenderjahr ein Schaltjahr ist.
|
||||
#
|
||||
# Die Gregorianische Schaltjahr-Regel lautet:
|
||||
# 1. Ein Jahr ist ein Schaltjahr, wenn es durch 4 teilbar ist (jahr % 4 == 0).
|
||||
# 2. AUSNAHME: Ist es durch 100 teilbar (jahr % 100 == 0), ist es KEIN Schaltjahr...
|
||||
# 3. AUSNAHME DER AUSNAHME: ...es sei denn, es ist auch durch 400 teilbar (jahr % 400 == 0)!
|
||||
#
|
||||
# Beispiele:
|
||||
# ist_schaltjahr(2024) -> True (durch 4 teilbar, nicht durch 100)
|
||||
# ist_schaltjahr(2023) -> False (nicht durch 4 teilbar)
|
||||
# ist_schaltjahr(1900) -> False (durch 100 teilbar, aber nicht durch 400)
|
||||
# ist_schaltjahr(2000) -> True (durch 400 teilbar)
|
||||
# ==============================================================================
|
||||
|
||||
def ist_schaltjahr(jahr: int) -> bool:
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Achterbahn-Zulassung
|
||||
#
|
||||
# Schreibe eine Funktion 'kann_achterbahn_fahren(groesse_cm: int, begleitung_erwachsen: bool) -> bool'.
|
||||
# Ein Freizeitpark hat folgende Sicherheitsbestimmungen:
|
||||
# - Ab 140 cm Körpergröße darf jede Person alleine mitfahren (True).
|
||||
# - Zwischen 120 cm und 139 cm darf eine Person NUR mitfahren, wenn
|
||||
# eine erwachsene Begleitperson dabei ist (begleitung_erwachsen == True).
|
||||
# - Unter 120 cm Körpergröße darf niemand mitfahren (immer False).
|
||||
#
|
||||
# Beispiele:
|
||||
# kann_achterbahn_fahren(145, False) -> True (Groß genug für Alleinfahrt)
|
||||
# kann_achterbahn_fahren(130, True) -> True (Mit Begleitung erlaubt)
|
||||
# kann_achterbahn_fahren(130, False) -> False (Ohne Begleitung verboten)
|
||||
# kann_achterbahn_fahren(115, True) -> False (Zu klein, auch mit Begleitung)
|
||||
# ==============================================================================
|
||||
|
||||
def kann_achterbahn_fahren(groesse_cm: int, begleitung_erwachsen: bool) -> bool:
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Interaktives Hauptprogramm zum Ausprobieren:
|
||||
# (Führe dieses Skript aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("🎢 BEDINGUNGEN & VERZWEIGUNGEN DEMO")
|
||||
print("=" * 60)
|
||||
|
||||
# 1. Kino-Test
|
||||
print("\n🎟️ --- Kino-Preisrechner ---")
|
||||
try:
|
||||
alter_eingabe = int(input("Alter des Besuchers: "))
|
||||
student_eingabe = input("Student/Schüler? (j/n): ").strip().lower() == "j"
|
||||
preis = ticket_preis(alter_eingabe, student_eingabe)
|
||||
if preis is not None:
|
||||
print(f"Ticketpreis: {preis:.2f} €")
|
||||
else:
|
||||
print("Implementiere TODO 1 für die Preisberechnung!")
|
||||
except ValueError:
|
||||
print("Ungültige Alterseingabe!")
|
||||
|
||||
# 2. Noten-Test
|
||||
print("\n📝 --- Notenspiegel-Rechner ---")
|
||||
try:
|
||||
punkte_eingabe = int(input("Erreichte Punkte (0-100): "))
|
||||
note = schulnote_text(punkte_eingabe)
|
||||
if note is not None:
|
||||
print(f"Ergebnis: {note}")
|
||||
else:
|
||||
print("Implementiere TODO 2 für die Notenberechnung!")
|
||||
except ValueError:
|
||||
print("Ungültige Punktezahl!")
|
||||
|
||||
# 3. Schaltjahr-Test
|
||||
print("\n📅 --- Schaltjahr-Prüfer ---")
|
||||
try:
|
||||
jahr_eingabe = int(input("Jahr eingeben (z.B. 2024): "))
|
||||
schalt = ist_schaltjahr(jahr_eingabe)
|
||||
if schalt is not None:
|
||||
print(f"Ist {jahr_eingabe} ein Schaltjahr? -> {'Ja! 🎉' if schalt else 'Nein.'}")
|
||||
else:
|
||||
print("Implementiere TODO 3 für die Schaltjahrprüfung!")
|
||||
except ValueError:
|
||||
print("Ungültiges Jahr!")
|
||||
|
||||
# 4. Achterbahn-Test
|
||||
print("\n🎢 --- Achterbahn-Einlasskontrolle ---")
|
||||
try:
|
||||
groesse = int(input("Körpergröße in cm (z.B. 135): "))
|
||||
begl = input("Erwachsene Begleitung dabei? (j/n): ").strip().lower() == "j"
|
||||
darf_fahren = kann_achterbahn_fahren(groesse, begl)
|
||||
if darf_fahren is not None:
|
||||
print(f"Darf Achterbahn fahren? -> {'Ja, viel Spaß! 🎢' if darf_fahren else 'Leider nein 🛑'}")
|
||||
else:
|
||||
print("Implementiere TODO 4 für die Achterbahn-Zulassung!")
|
||||
except ValueError:
|
||||
print("Ungültige Größenangabe!")
|
||||
291
g04_verzweigungen_und_bedingungen/index.html
Normal file
291
g04_verzweigungen_und_bedingungen/index.html
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G04: Bedingungen & Verzweigungen</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g03_ein_und_ausgabe/index.html">← Kapitel G03</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G04</span>
|
||||
<span>›</span>
|
||||
<a href="../g05_schleifen_und_wiederholungen/index.html">Kapitel G05 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G04 • Schulabgleich 08.0</div>
|
||||
<h1>Bedingungen & Verzweigungen 🛤️🔀</h1>
|
||||
<p>Lerne, wie dein Code mit <code>if</code>, <code>elif</code> und <code>else</code> intelligente Entscheidungen trifft und wie du logische Operatoren meisterst.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie & Einführung -->
|
||||
<section class="card">
|
||||
<h2>1. Die Eisenbahn-Weichen-Analogie 🚂</h2>
|
||||
|
||||
<p>
|
||||
Code wird standardmäßig von oben nach unten Zeile für Zeile ausgeführt. Doch oft soll ein Programm je nach Situation einen anderen Pfad einschlagen: Ein Kinokassen-System berechnet für Kinder einen anderen Preis als für Erwachsene.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🛤️ Das Eisenbahngleis & die Weichen:</div>
|
||||
Stell dir den Programmlauf wie einen Zug vor, der auf ein Weichensystem zufährt:
|
||||
<br>1. <strong>Das Signal (Bedingung):</strong> Die Weiche prüft: <em>"Ist das Alter unter 12?"</em>
|
||||
<br>2. <strong>Grünes Signal (True):</strong> Der Zug biegt auf das Kindertarif-Gleis ab und führt dessen Code aus.
|
||||
<br>3. <strong>Rotes Signal (False):</strong> Der Zug fährt weiter zur nächsten Weiche (<code>elif</code>).
|
||||
<br>4. <strong>Das Ausweichgleis (else):</strong> Wenn keines der Signale grün war, nimmt der Zug das Standardgleis.
|
||||
<br>5. <strong>Weiterfahrt:</strong> Hinter der Weichenanlage laufen alle Gleise wieder auf der Hauptstrecke zusammen!
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Syntax & Vergleichsoperatoren -->
|
||||
<section class="card">
|
||||
<h2>2. Syntax von <code>if / elif / else</code> & Vergleichsoperatoren</h2>
|
||||
|
||||
<p>
|
||||
In Python werden Verzweigungen mit Doppelpunkt <code>:</code> eingeleitet und der zugehörige Codeblock muss <strong>genau 4 Leerzeichen</strong> eingerückt sein.
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Kino-Tarif-Weiche</span>
|
||||
</div>
|
||||
<pre><span class="kw">if</span> <span class="var">alter</span> < <span class="num">12</span>:
|
||||
<span class="var">preis</span> = <span class="num">6.00</span> <span class="cm"># 4 Leerzeichen Einrückung</span>
|
||||
<span class="kw">elif</span> <span class="var">alter</span> >= <span class="num">65</span>:
|
||||
<span class="var">preis</span> = <span class="num">8.50</span>
|
||||
<span class="kw">elif</span> <span class="var">ist_student</span>:
|
||||
<span class="var">preis</span> = <span class="num">9.50</span>
|
||||
<span class="kw">else</span>:
|
||||
<span class="var">preis</span> = <span class="num">12.00</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Häufige Fehlerquelle: = vs. ==</div>
|
||||
- <code>=</code> (einfaches Istgleich) ist eine <strong>Zuweisung</strong>: <code>punkte = 10</code>.<br>
|
||||
- <code>==</code> (doppeltes Istgleich) ist ein <strong>Vergleich</strong>: <code>if punkte == 10:</code>.
|
||||
</div>
|
||||
|
||||
<h3>Die 6 Vergleichsoperatoren:</h3>
|
||||
<div style="overflow-x: auto; margin: 15px 0;">
|
||||
<table style="width: 100%; border-collapse: collapse; text-align: left; background: white; border-radius: 8px; overflow: hidden; box-shadow: var(--shadow-sm);">
|
||||
<thead>
|
||||
<tr style="background: var(--primary); color: white;">
|
||||
<th style="padding: 10px 14px;">Operator</th>
|
||||
<th style="padding: 10px 14px;">Bedeutung</th>
|
||||
<th style="padding: 10px 14px;">Beispiel</th>
|
||||
<th style="padding: 10px 14px;">Ergebnis</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 8px 14px;"><code>==</code></td>
|
||||
<td style="padding: 8px 14px;">Gleich</td>
|
||||
<td style="padding: 8px 14px;"><code>5 == 5</code></td>
|
||||
<td style="padding: 8px 14px;"><strong style="color: var(--success);">True</strong></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 8px 14px;"><code>!=</code></td>
|
||||
<td style="padding: 8px 14px;">Ungleich</td>
|
||||
<td style="padding: 8px 14px;"><code>5 != 3</code></td>
|
||||
<td style="padding: 8px 14px;"><strong style="color: var(--success);">True</strong></td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 8px 14px;"><code><</code> / <code>></code></td>
|
||||
<td style="padding: 8px 14px;">Kleiner als / Größer als</td>
|
||||
<td style="padding: 8px 14px;"><code>10 < 20</code></td>
|
||||
<td style="padding: 8px 14px;"><strong style="color: var(--success);">True</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px 14px;"><code><=</code> / <code>>=</code></td>
|
||||
<td style="padding: 8px 14px;">Kleiner gleich / Größer gleich</td>
|
||||
<td style="padding: 8px 14px;"><code>18 >= 18</code></td>
|
||||
<td style="padding: 8px 14px;"><strong style="color: var(--success);">True</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Logische Operatoren & Wahrheitstabellen -->
|
||||
<section class="card">
|
||||
<h2>3. Logische Operatoren & Wahrheitstabellen 🧪</h2>
|
||||
|
||||
<p>
|
||||
Bedingungen lassen sich mit <code>and</code>, <code>or</code> und <code>not</code> kombinieren:
|
||||
</p>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 15px; margin: 15px 0;">
|
||||
|
||||
<!-- AND Tabelle -->
|
||||
<div style="background: white; border: 1px solid var(--border-color); border-radius: 8px; padding: 14px; box-shadow: var(--shadow-sm);">
|
||||
<h4 style="color: var(--primary); margin-bottom: 8px;"><code>and</code> (Beide wahr)</h4>
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 0.88rem;">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light);">
|
||||
<th style="padding: 4px 6px;">A</th>
|
||||
<th style="padding: 4px 6px;">B</th>
|
||||
<th style="padding: 4px 6px;">A and B</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px; color: var(--success); font-weight: bold;">True</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px; color: var(--danger);">False</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px; color: var(--danger);">False</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px; color: var(--danger);">False</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- OR Tabelle -->
|
||||
<div style="background: white; border: 1px solid var(--border-color); border-radius: 8px; padding: 14px; box-shadow: var(--shadow-sm);">
|
||||
<h4 style="color: var(--secondary); margin-bottom: 8px;"><code>or</code> (Mind. eins wahr)</h4>
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 0.88rem;">
|
||||
<thead>
|
||||
<tr style="background: #e0f2fe;">
|
||||
<th style="padding: 4px 6px;">A</th>
|
||||
<th style="padding: 4px 6px;">B</th>
|
||||
<th style="padding: 4px 6px;">A or B</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px; color: var(--success); font-weight: bold;">True</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px; color: var(--success); font-weight: bold;">True</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px; color: var(--success); font-weight: bold;">True</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px; color: var(--danger);">False</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- NOT Tabelle -->
|
||||
<div style="background: white; border: 1px solid var(--border-color); border-radius: 8px; padding: 14px; box-shadow: var(--shadow-sm);">
|
||||
<h4 style="color: var(--purple); margin-bottom: 8px;"><code>not</code> (Verneinung)</h4>
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 0.88rem;">
|
||||
<thead>
|
||||
<tr style="background: var(--purple-light);">
|
||||
<th style="padding: 4px 6px;">A</th>
|
||||
<th style="padding: 4px 6px;">not A</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="padding: 4px 6px;">True</td><td style="padding: 4px 6px; color: var(--danger); font-weight: bold;">False</td></tr>
|
||||
<tr><td style="padding: 4px 6px;">False</td><td style="padding: 4px 6px; color: var(--success); font-weight: bold;">True</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">💡 Tipp: Klammern setzen für klare Lesbarkeit</div>
|
||||
Genau wie in der Mathematik gilt: Klammern <code>(...)</code> binden stärker und machen deinen Code absolut unmissverständlich!<br>
|
||||
<code>darf_fahren = (groesse >= 140) or (groesse >= 120 and begleitung)</code>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Deine Aufgaben -->
|
||||
<section class="card">
|
||||
<h2>4. 📝 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne <code>g04_verzweigungen_und_bedingungen/aufgabe.py</code> und setze folgende 4 Funktionen um:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>ticket_preis(alter: int, ist_student: bool) -> float</code></strong><br>
|
||||
Berechne den Kinopreis: <code>alter < 12</code> → 6.00 €, <code>alter >= 65</code> → 8.50 €, sonst bei <code>ist_student == True</code> → 9.50 €, sonst → 12.00 €.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>schulnote_text(punkte: int) -> str</code></strong><br>
|
||||
Notenspiegel: Ungültig bei <code>< 0</code> oder <code>> 100</code> ("Ungültige Punktezahl"), ab 90 ("Sehr gut"), ab 75 ("Gut"), ab 60 ("Befriedigend"), ab 50 ("Genügend"), sonst ("Nicht genügend").
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>ist_schaltjahr(jahr: int) -> bool</code></strong><br>
|
||||
Prüfe die Schaltjahr-Regel: Durch 4 teilbar, aber nicht durch 100 (außer wenn durch 400 teilbar).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>kann_achterbahn_fahren(groesse_cm: int, begleitung_erwachsen: bool) -> bool</code></strong><br>
|
||||
Freizeitpark-Zulassung: Ab 140 cm immer erlaubt (True). Zwischen 120 und 139 cm nur mit erwachsener Begleitung (True). Unter 120 cm nie erlaubt (False).
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 2 (Reihenfolge der Notenstufen)</summary>
|
||||
<div class="details-content">
|
||||
<p>Prüfe zuerst die ungültigen Werte (<code>punkte < 0 or punkte > 100</code>). Danach kannst du bequem von oben nach unten mit <code>>= 90</code>, <code>>= 75</code> usw. prüfen!</p>
|
||||
<div class="code-container">
|
||||
<pre><code>if punkte < 0 or punkte > 100:
|
||||
return "Ungültige Punktezahl"
|
||||
elif punkte >= 90:
|
||||
return "Sehr gut"
|
||||
# ...</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Modulo % & Schaltjahre)</summary>
|
||||
<div class="details-content">
|
||||
<p>Mit dem Modulo-Operator <code>%</code> prüfst du die Teilbarkeit (Restwert der Division ist 0):</p>
|
||||
<div class="code-container">
|
||||
<pre><code>if (jahr % 4 == 0 and jahr % 100 != 0) or (jahr % 400 == 0):
|
||||
return True
|
||||
return False</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 5. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. 🧪 Automatische Tests & Überprüfung</h2>
|
||||
<p>Führe das Testskript im Terminal aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<p>Oder teste das interaktive Programm mit eigenen Eingaben:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Interaktiver Test</span></div>
|
||||
<pre><code>python3 aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g03_ein_und_ausgabe/index.html" class="btn btn-secondary">← Zurück zu Kapitel G03</a>
|
||||
<a href="../g05_schleifen_und_wiederholungen/index.html" class="btn">Weiter zu Kapitel G05: Schleifen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
97
g04_verzweigungen_und_bedingungen/musterloesung.py
Normal file
97
g04_verzweigungen_und_bedingungen/musterloesung.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"""
|
||||
Kapitel G04: Verzweigungen & Bedingungen (Schulabgleich 08.0)
|
||||
============================================================
|
||||
Musterlösung mit sauberen if/elif/else-Verzweigungen und logischen Operatoren.
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Kinokarten-Preisrechner
|
||||
# ==============================================================================
|
||||
def ticket_preis(alter: int, ist_student: bool) -> float:
|
||||
"""Berechnet den Kinokartenpreis basierend auf Alter und Schüler/Studenten-Status."""
|
||||
if alter < 12:
|
||||
return 6.0
|
||||
elif alter >= 65:
|
||||
return 8.5
|
||||
elif ist_student:
|
||||
return 9.5
|
||||
else:
|
||||
return 12.0
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schulnoten-Ermittlung
|
||||
# ==============================================================================
|
||||
def schulnote_text(punkte: int) -> str:
|
||||
"""Gibt die passende Textnote für eine Punktezahl zwischen 0 und 100 zurück."""
|
||||
if punkte < 0 or punkte > 100:
|
||||
return "Ungültige Punktezahl"
|
||||
elif punkte >= 90:
|
||||
return "Sehr gut"
|
||||
elif punkte >= 75:
|
||||
return "Gut"
|
||||
elif punkte >= 60:
|
||||
return "Befriedigend"
|
||||
elif punkte >= 50:
|
||||
return "Genügend"
|
||||
else:
|
||||
return "Nicht genügend"
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schaltjahr-Erkennung
|
||||
# ==============================================================================
|
||||
def ist_schaltjahr(jahr: int) -> bool:
|
||||
"""
|
||||
Ermittelt nach den Gregorianischen Kalenderregeln, ob ein Jahr ein Schaltjahr ist.
|
||||
Teilbar durch 4, aber nicht durch 100 (außer wenn durch 400 teilbar).
|
||||
"""
|
||||
if (jahr % 4 == 0 and jahr % 100 != 0) or (jahr % 400 == 0):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Achterbahn-Zulassung
|
||||
# ==============================================================================
|
||||
def kann_achterbahn_fahren(groesse_cm: int, begleitung_erwachsen: bool) -> bool:
|
||||
"""Prüft, ob eine Person (mit oder ohne Begleitung) groß genug für die Fahrt ist."""
|
||||
if groesse_cm >= 140:
|
||||
return True
|
||||
elif groesse_cm >= 120 and begleitung_erwachsen:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Interaktives Hauptprogramm
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("🎢 BEDINGUNGEN & VERZWEIGUNGEN (MUSTERLÖSUNG)")
|
||||
print("=" * 60)
|
||||
|
||||
print("Kino:", ticket_preis(8, False), "€ (Kind)")
|
||||
print("Kino:", ticket_preis(20, True), "€ (Student)")
|
||||
print("Kino:", ticket_preis(30, False), "€ (Erwachsen)")
|
||||
print("Kino:", ticket_preis(70, False), "€ (Senior)")
|
||||
|
||||
print("\nNoten:")
|
||||
print("95 Punkte:", schulnote_text(95))
|
||||
print("75 Punkte:", schulnote_text(75))
|
||||
print("50 Punkte:", schulnote_text(50))
|
||||
print("30 Punkte:", schulnote_text(30))
|
||||
print("110 Punkte:", schulnote_text(110))
|
||||
|
||||
print("\nSchaltjahre:")
|
||||
print("2024:", ist_schaltjahr(2024))
|
||||
print("2023:", ist_schaltjahr(2023))
|
||||
print("1900:", ist_schaltjahr(1900))
|
||||
print("2000:", ist_schaltjahr(2000))
|
||||
|
||||
print("\nAchterbahn:")
|
||||
print("145cm alleine:", kann_achterbahn_fahren(145, False))
|
||||
print("130cm mit Begleitung:", kann_achterbahn_fahren(130, True))
|
||||
print("130cm alleine:", kann_achterbahn_fahren(130, False))
|
||||
print("110cm mit Begleitung:", kann_achterbahn_fahren(110, True))
|
||||
160
g04_verzweigungen_und_bedingungen/test_aufgabe.py
Normal file
160
g04_verzweigungen_und_bedingungen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import unittest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import importlib.util
|
||||
|
||||
# Pfad zum aktuellen Kapitelverzeichnis
|
||||
CHAPTER_DIR = Path(__file__).parent
|
||||
|
||||
|
||||
def lade_modul(modul_name="aufgabe"):
|
||||
"""Lädt das Modul (aufgabe oder musterloesung) isoliert aus dem Kapitelverzeichnis."""
|
||||
dateipfad = CHAPTER_DIR / f"{modul_name}.py"
|
||||
if not dateipfad.exists():
|
||||
raise FileNotFoundError(f"Datei '{dateipfad}' wurde nicht gefunden.")
|
||||
spec = importlib.util.spec_from_file_location(f"g04_{modul_name}", dateipfad)
|
||||
modul = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(modul)
|
||||
return modul
|
||||
|
||||
|
||||
class TestKapitelG04(unittest.TestCase):
|
||||
"""
|
||||
Testsuite für Kapitel G04: Verzweigungen & Bedingungen
|
||||
Überprüft if/elif/else-Verzweigungen, Grenzwerte und logische Operatoren.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.target_modul = getattr(cls, "modul_name", "aufgabe")
|
||||
try:
|
||||
cls.mod = lade_modul(cls.target_modul)
|
||||
except SyntaxError as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"SyntaxError in '{cls.target_modul}.py': {e}"
|
||||
except Exception as e:
|
||||
cls.mod = None
|
||||
cls.import_error = f"Fehler beim Laden von '{cls.target_modul}.py': {e}"
|
||||
|
||||
def _get_modul(self):
|
||||
if getattr(self, "mod", None) is None:
|
||||
err = getattr(self, "import_error", f"{self.target_modul}.py konnte nicht geladen werden")
|
||||
self.fail(f"❌ {err}")
|
||||
return self.mod
|
||||
|
||||
def test_01_ticket_preis_alle_tarife(self):
|
||||
"""Prüft TODO 1: ticket_preis(alter, ist_student) für alle Altersgruppen."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "ticket_preis"),
|
||||
"Fehler: Funktion 'ticket_preis' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# Kindertarif (< 12 Jahre): 6.00 €
|
||||
self.assertEqual(mod.ticket_preis(5, False), 6.0, "Alter 5 sollte 6.00 € kosten (Kindertarif)!")
|
||||
self.assertEqual(mod.ticket_preis(11, False), 6.0, "Alter 11 sollte 6.00 € kosten (Kindertarif)!")
|
||||
self.assertEqual(mod.ticket_preis(11, True), 6.0, "Kinder zahlen immer 6.00 €!")
|
||||
|
||||
# Seniorentarif (>= 65 Jahre): 8.50 €
|
||||
self.assertEqual(mod.ticket_preis(65, False), 8.5, "Alter 65 sollte 8.50 € kosten (Seniorentarif)!")
|
||||
self.assertEqual(mod.ticket_preis(80, False), 8.5, "Alter 80 sollte 8.50 € kosten (Seniorentarif)!")
|
||||
self.assertEqual(mod.ticket_preis(70, True), 8.5, "Senioren ab 65 zahlen 8.50 €!")
|
||||
|
||||
# Studenten- / Ermäßigungstarif (12 <= alter < 65 und ist_student == True): 9.50 €
|
||||
self.assertEqual(mod.ticket_preis(12, True), 9.5, "Schüler/Student mit 12 Jahren sollte 9.50 € kosten!")
|
||||
self.assertEqual(mod.ticket_preis(22, True), 9.5, "Student mit 22 Jahren sollte 9.50 € kosten!")
|
||||
self.assertEqual(mod.ticket_preis(64, True), 9.5, "Student mit 64 Jahren sollte 9.50 € kosten!")
|
||||
|
||||
# Regulärer Erwachsenentarif (12 <= alter < 65 und ist_student == False): 12.00 €
|
||||
self.assertEqual(mod.ticket_preis(12, False), 12.0, "Regulärer Preis ab 12 Jahren ohne Ermäßigung ist 12.00 €!")
|
||||
self.assertEqual(mod.ticket_preis(35, False), 12.0, "Erwachsener (35) ohne Ermäßigung sollte 12.00 € zahlen!")
|
||||
self.assertEqual(mod.ticket_preis(64, False), 12.0, "Erwachsener (64) ohne Ermäßigung sollte 12.00 € zahlen!")
|
||||
|
||||
def test_02_schulnote_text_grenzwerte(self):
|
||||
"""Prüft TODO 2: schulnote_text(punkte) inklusive aller Grenzwerte."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "schulnote_text"),
|
||||
"Fehler: Funktion 'schulnote_text' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# 90..100: "Sehr gut"
|
||||
self.assertEqual(mod.schulnote_text(100), "Sehr gut", "100 Punkte müssen 'Sehr gut' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(90), "Sehr gut", "Genau 90 Punkte müssen 'Sehr gut' ergeben (Grenzwert)!")
|
||||
|
||||
# 75..89: "Gut"
|
||||
self.assertEqual(mod.schulnote_text(89), "Gut", "89 Punkte müssen 'Gut' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(75), "Gut", "Genau 75 Punkte müssen 'Gut' ergeben (Grenzwert)!")
|
||||
|
||||
# 60..74: "Befriedigend"
|
||||
self.assertEqual(mod.schulnote_text(74), "Befriedigend", "74 Punkte müssen 'Befriedigend' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(60), "Befriedigend", "Genau 60 Punkte müssen 'Befriedigend' ergeben (Grenzwert)!")
|
||||
|
||||
# 50..59: "Genügend"
|
||||
self.assertEqual(mod.schulnote_text(59), "Genügend", "59 Punkte müssen 'Genügend' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(50), "Genügend", "Genau 50 Punkte müssen 'Genügend' ergeben (Grenzwert)!")
|
||||
|
||||
# 0..49: "Nicht genügend"
|
||||
self.assertEqual(mod.schulnote_text(49), "Nicht genügend", "49 Punkte müssen 'Nicht genügend' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(0), "Nicht genügend", "0 Punkte müssen 'Nicht genügend' ergeben!")
|
||||
|
||||
# Ungültig (< 0 oder > 100)
|
||||
self.assertEqual(mod.schulnote_text(-1), "Ungültige Punktezahl", "-1 Punkt muss 'Ungültige Punktezahl' ergeben!")
|
||||
self.assertEqual(mod.schulnote_text(101), "Ungültige Punktezahl", "101 Punkte müssen 'Ungültige Punktezahl' ergeben!")
|
||||
|
||||
def test_03_ist_schaltjahr_regeln(self):
|
||||
"""Prüft TODO 3: ist_schaltjahr(jahr) mit allen Gregorianischen Ausnahmen."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "ist_schaltjahr"),
|
||||
"Fehler: Funktion 'ist_schaltjahr' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# Normale Schaltjahre (durch 4 teilbar, nicht durch 100):
|
||||
self.assertTrue(mod.ist_schaltjahr(2024), "2024 ist ein Schaltjahr (durch 4 teilbar)!")
|
||||
self.assertTrue(mod.ist_schaltjahr(2020), "2020 ist ein Schaltjahr!")
|
||||
self.assertTrue(mod.ist_schaltjahr(2016), "2016 ist ein Schaltjahr!")
|
||||
|
||||
# Normale Nicht-Schaltjahre (nicht durch 4 teilbar):
|
||||
self.assertFalse(mod.ist_schaltjahr(2023), "2023 ist kein Schaltjahr!")
|
||||
self.assertFalse(mod.ist_schaltjahr(2025), "2025 ist kein Schaltjahr!")
|
||||
|
||||
# Säkularjahre / Jahrhundert-Regel:
|
||||
# Durch 100 teilbar, aber NICHT durch 400 -> KEIN Schaltjahr!
|
||||
self.assertFalse(mod.ist_schaltjahr(1900), "1900 ist KEIN Schaltjahr (durch 100 teilbar, aber nicht durch 400)!")
|
||||
self.assertFalse(mod.ist_schaltjahr(2100), "2100 ist KEIN Schaltjahr (durch 100 teilbar, aber nicht durch 400)!")
|
||||
self.assertFalse(mod.ist_schaltjahr(1800), "1800 ist KEIN Schaltjahr!")
|
||||
|
||||
# 400er-Regel:
|
||||
# Durch 400 teilbar -> IST ein Schaltjahr!
|
||||
self.assertTrue(mod.ist_schaltjahr(2000), "2000 IST ein Schaltjahr (durch 400 teilbar)!")
|
||||
self.assertTrue(mod.ist_schaltjahr(2400), "2400 IST ein Schaltjahr (durch 400 teilbar)!")
|
||||
self.assertTrue(mod.ist_schaltjahr(1600), "1600 IST ein Schaltjahr (durch 400 teilbar)!")
|
||||
|
||||
def test_04_kann_achterbahn_fahren(self):
|
||||
"""Prüft TODO 4: kann_achterbahn_fahren(groesse_cm, begleitung_erwachsen)."""
|
||||
mod = self._get_modul()
|
||||
self.assertTrue(
|
||||
hasattr(mod, "kann_achterbahn_fahren"),
|
||||
"Fehler: Funktion 'kann_achterbahn_fahren' fehlt in aufgabe.py!"
|
||||
)
|
||||
|
||||
# Ab 140 cm: Immer erlaubt (auch ohne Begleitung)
|
||||
self.assertTrue(mod.kann_achterbahn_fahren(140, False), "Genau 140 cm darf alleine fahren!")
|
||||
self.assertTrue(mod.kann_achterbahn_fahren(155, False), "155 cm darf alleine fahren!")
|
||||
self.assertTrue(mod.kann_achterbahn_fahren(140, True), "140 cm mit Begleitung darf natürlich auch fahren!")
|
||||
|
||||
# 120 bis 139 cm: NUR mit erwachsener Begleitung
|
||||
self.assertTrue(mod.kann_achterbahn_fahren(120, True), "120 cm mit Begleitung ist erlaubt!")
|
||||
self.assertTrue(mod.kann_achterbahn_fahren(135, True), "135 cm mit Begleitung ist erlaubt!")
|
||||
self.assertFalse(mod.kann_achterbahn_fahren(120, False), "120 cm OHNE Begleitung ist verboten!")
|
||||
self.assertFalse(mod.kann_achterbahn_fahren(139, False), "139 cm OHNE Begleitung ist verboten!")
|
||||
|
||||
# Unter 120 cm: Grundsätzlich verboten (auch mit Begleitung)
|
||||
self.assertFalse(mod.kann_achterbahn_fahren(119, True), "119 cm ist zu klein, auch mit Begleitung!")
|
||||
self.assertFalse(mod.kann_achterbahn_fahren(119, False), "119 cm ohne Begleitung ist verboten!")
|
||||
self.assertFalse(mod.kann_achterbahn_fahren(95, True), "95 cm ist zu klein!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
196
g05_schleifen_und_wiederholungen/README.md
Normal file
196
g05_schleifen_und_wiederholungen/README.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# Kapitel G05: Schleifen & Wiederholungen 🎡🔄
|
||||
|
||||
Willkommen zu **Kapitel G05** unseres Python-Grundlagen-Lehrpfads!
|
||||
Dieses Kapitel entspricht den Modulen **09.1 & 09.2** deines Informatik-Skriptums.
|
||||
|
||||
Computer sind genial darin, dieselbe Aufgabe tausende oder millionen Male in Millisekunden auszuführen – ohne müde zu werden oder Fehler zu machen. Das Werkzeug dafür sind **Schleifen (Loops)**!
|
||||
|
||||
---
|
||||
|
||||
## 🎡 Die Karussell- & Riesenrad-Analogie
|
||||
|
||||
Stell dir einen Jahrmarkt vor:
|
||||
- **`for`-Schleife (Zählschleife):** Wie ein Karussell mit Wertmarken. Du kaufst dir 5 Runden. Der Automat zählt mit: Runde 1, 2, 3, 4, 5. Nach 5 Runden stoppt das Karussell automatisch.
|
||||
- **`while`-Schleife (Bedingungsschleife):** Wie ein Riesenrad, das sich dreht, **solange** die Musik spielt. Sobald die Musik stoppt (Bedingung wird `False`), hält das Rad an.
|
||||
|
||||
```
|
||||
[ FOR-SCHLEIFE ] [ WHILE-SCHLEIFE ]
|
||||
"Fahre genau 5 Runden!" "Fahre, SOLANGE Musik läuft!"
|
||||
┌───────────┐ ┌───────────┐
|
||||
│ Runde 1/5 │ │ Musik da? │ ── Nein ──> Stopp
|
||||
│ Runde 2/5 │ └─────┬─────┘
|
||||
│ Runde 3/5 │ │ Ja
|
||||
│ Runde 4/5 │ ┌─────▼─────┐
|
||||
│ Runde 5/5 │ │ 1 Runde │
|
||||
└─────┬─────┘ └─────┬─────┘
|
||||
▼ │
|
||||
FERTIG └───────── Wiederholen!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Die Zählschleife: `for` und die `range()`-Funktion
|
||||
|
||||
Wenn du im Voraus weißt, **wie oft** etwas wiederholt werden soll, ist die `for`-Schleife die perfekte Wahl.
|
||||
|
||||
### Wie funktioniert `range()`?
|
||||
|
||||
Die `range()`-Funktion erzeugt eine Zahlenfolge. **Wichtigste Regel:** Das `stop`-Element ist **immer exklusiv** (wird nicht mehr erreicht)!
|
||||
|
||||
```
|
||||
range(stop) -> 0 bis stop - 1
|
||||
range(start, stop) -> start bis stop - 1
|
||||
range(start, stop, step) -> start bis stop - 1 mit Schrittweite step
|
||||
```
|
||||
|
||||
#### Visualisierung:
|
||||
```
|
||||
range(1, 6) ──> [ 1, 2, 3, 4, 5 ] (6 ist NICHT dabei!)
|
||||
range(0, 10, 2) ─> [ 0, 2, 4, 6, 8 ] (nur gerade Zahlen!)
|
||||
range(5, 0, -1) ─> [ 5, 4, 3, 2, 1 ] (rückwärts zählen!)
|
||||
```
|
||||
|
||||
```python
|
||||
# Einfaches Beispiel:
|
||||
for i in range(1, 6):
|
||||
print(f"Runde {i}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Die Bedingungsschleife: `while`
|
||||
|
||||
Wenn du vorher **nicht genau weißt**, wie viele Durchläufe nötig sind, sondern die Wiederholung an eine **Bedingung** geknüpft ist:
|
||||
|
||||
```python
|
||||
energie = 3
|
||||
while energie > 0:
|
||||
print(f"Roboter läuft... Energie: {energie}")
|
||||
energie -= 1 # ⚠️ WICHTIG: Schleifenzähler verändern!
|
||||
|
||||
print("Roboter hat keine Energie mehr.")
|
||||
```
|
||||
|
||||
### 🛑 Die Gefahr der Endlosschleife (Infinite Loop)
|
||||
|
||||
Wenn die Bedingung einer `while`-Schleife niemals `False` wird, läuft das Programm für immer und friert ein:
|
||||
|
||||
```python
|
||||
# 💥 GEFÄHRLICH: Endlosschleife!
|
||||
x = 1
|
||||
while x > 0:
|
||||
print(x)
|
||||
# Vergessen, x zu verändern -> x bleibt immer 1 -> Bedingung immer True!
|
||||
```
|
||||
|
||||
> **Tipp zum Abbrechen:** Falls dein Programm in einer Endlosschleife festhängt, drücke im Terminal <kbd>Strg</kbd> + <kbd>C</kbd> (Ctrl+C).
|
||||
|
||||
---
|
||||
|
||||
## 3. Schleifen steuern: `break` & `continue`
|
||||
|
||||
Manchmal möchtest du eine Schleife vorzeitig beenden oder eine Runde überspringen:
|
||||
|
||||
- **`break` (Die Notbremse):** Verlässt die Schleife **sofort**, egal wie viele Runden noch übrig wären.
|
||||
- **`continue` (Nächste Runde):** Bricht nur den **aktuellen Durchlauf** ab und springt direkt zur nächsten Runde.
|
||||
|
||||
```python
|
||||
# Beispiel break:
|
||||
for zahl in range(1, 10):
|
||||
if zahl == 5:
|
||||
print("Treffer! Schleife wird abgebrochen.")
|
||||
break
|
||||
print(zahl) # Gibt 1, 2, 3, 4 aus
|
||||
|
||||
# Beispiel continue:
|
||||
for zahl in range(1, 6):
|
||||
if zahl == 3:
|
||||
print("Zahl 3 wird übersprungen!")
|
||||
continue
|
||||
print(zahl) # Gibt 1, 2, 4, 5 aus
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Das Schleifen-Akkumulator-Muster 🧺
|
||||
|
||||
Ein **Akkumulator** ist eine Hilfsvariable, die **vor** der Schleife erstellt wird und in jedem Schleifendurchlauf einen neuen Wert aufsammelt.
|
||||
|
||||
```python
|
||||
# 1. Summen-Akkumulator (Startwert: 0)
|
||||
summe = 0
|
||||
for x in [10, 20, 30]:
|
||||
summe += x # summe = summe + x
|
||||
print("Summe:", summe) # 60
|
||||
|
||||
# 2. Zähler-Akkumulator (Startwert: 0)
|
||||
anzahl_gerade = 0
|
||||
for x in range(1, 11):
|
||||
if x % 2 == 0:
|
||||
anzahl_gerade += 1
|
||||
print("Gerade Zahlen:", anzahl_gerade) # 5
|
||||
|
||||
# 3. Produkt-Akkumulator (Startwert: 1, NIEMALS 0!)
|
||||
produkt = 1
|
||||
for x in range(1, 5):
|
||||
produkt *= x # 1 * 2 * 3 * 4
|
||||
print("Produkt:", produkt) # 24
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 🌟 Praxisbeispiele
|
||||
|
||||
### Beispiel A: Kleines Einmaleins (Verschachtelte Schleifen)
|
||||
```python
|
||||
for zeile in range(1, 4):
|
||||
for spalte in range(1, 4):
|
||||
ergebnis = zeile * spalte
|
||||
print(f"{zeile}x{spalte}={ergebnis:2d}", end=" ")
|
||||
print() # Zeilenumbruch
|
||||
```
|
||||
|
||||
### Beispiel B: Zahlen-Ratespiel mit `while` und `break`
|
||||
```python
|
||||
geheime_zahl = 7
|
||||
versuche = 0
|
||||
|
||||
while True:
|
||||
versuche += 1
|
||||
tipp = int(input("Rate eine Zahl zwischen 1 und 10: "))
|
||||
if tipp == geheime_zahl:
|
||||
print(f"🎉 Richtig erraten nach {versuche} Versuchen!")
|
||||
break
|
||||
elif tipp < geheime_zahl:
|
||||
print("Zu klein!")
|
||||
else:
|
||||
print("Zu groß!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Die 3 häufigsten Anfängerfehler
|
||||
|
||||
1. **Off-by-One Fehler bei `range()`:**
|
||||
- `range(1, 5)` läuft nur bis 4! Wenn du die 5 inklusive haben willst, schreibe `range(1, 6)`.
|
||||
2. **Akkumulator in der Schleife zurücksetzen:**
|
||||
- Wenn du `summe = 0` **in** der Schleife schreibst, wird die Summe in jeder Runde gelöscht! Der Startwert muss **vor** der Schleife stehen.
|
||||
3. **Endlosschleife bei `while`:**
|
||||
- Vergiss nicht, die Variable in der `while`-Bedingung innerhalb der Schleife anzupassen (`i += 1` oder `n //= 10`).
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `aufgabe.py` und bearbeite die Aufgaben:
|
||||
1. **TODO 1:** `summe_bis(n: int) -> int` – Berechnet $1 + 2 + \dots + n$.
|
||||
2. **TODO 2:** `fakultaet(n: int) -> int` – Berechnet $n! = 1 \cdot 2 \cdots n$.
|
||||
3. **TODO 3:** `zaehle_gerade_zahlen(start: int, ende: int) -> int` – Zählt gerade Zahlen.
|
||||
4. **TODO 4:** `ist_primzahl(n: int) -> bool` – Prüft Primzahlen.
|
||||
5. **TODO 5:** `quorsumme(n: int) -> int` – Berechnet die Quersumme mit einer `while`-Schleife.
|
||||
|
||||
### Testen:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
Sobald alle 5 Tests grün sind (`OK`), kannst du zu Kapitel G06 weitergehen!
|
||||
167
g05_schleifen_und_wiederholungen/aufgabe.py
Normal file
167
g05_schleifen_und_wiederholungen/aufgabe.py
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
"""
|
||||
Kapitel G05: Schleifen & Wiederholungen – Aufgabenblatt
|
||||
======================================================
|
||||
Schulabgleich: 09.1 & 09.2
|
||||
|
||||
In diesem Kapitel lernst du, wie Wiederholungen in Python funktionieren:
|
||||
- for-Schleifen mit range()
|
||||
- while-Schleifen mit Bedingungen
|
||||
- Schleifen-Akkumulatoren (Summen, Zähler, Produkte)
|
||||
- Vorzeitiger Abbruch mit break und Weiterspringen mit continue
|
||||
|
||||
Bearbeite die Aufgaben von TODO 1 bis TODO 5.
|
||||
Teste deine Lösungen jederzeit im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Schreibe die Funktion "summe_bis(n: int) -> int".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Berechnet die Summe aller ganzen Zahlen von 1 bis n (inklusive).
|
||||
# Beispiel: summe_bis(5) = 1 + 2 + 3 + 4 + 5 = 15.
|
||||
#
|
||||
# Regeln:
|
||||
# - Wenn n <= 0 ist, soll 0 zurückgegeben werden.
|
||||
# - Nutze eine for-Schleife mit range(1, n + 1) und einen Akkumulator (summe = 0).
|
||||
# ==============================================================================
|
||||
|
||||
def summe_bis(n: int) -> int:
|
||||
"""Berechnet 1 + 2 + ... + n."""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schreibe die Funktion "fakultaet(n: int) -> int".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Die Fakultät n! ist das Produkt aller ganzen Zahlen von 1 bis n.
|
||||
# Beispiel: fakultaet(5) = 1 * 2 * 3 * 4 * 5 = 120.
|
||||
#
|
||||
# Sonderregeln:
|
||||
# - Für n = 0 ist die Fakultät mathematisch definiert als 1 (fakultaet(0) == 1).
|
||||
# - Für negative Zahlen (n < 0) ist die Fakultät nicht definiert.
|
||||
# Löse in diesem Fall einen ValueError aus:
|
||||
# raise ValueError("Fakultät ist für negative Zahlen nicht definiert")
|
||||
# - Nutze eine for-Schleife mit range(1, n + 1) und einen Akkumulator (produkt = 1).
|
||||
# ==============================================================================
|
||||
|
||||
def fakultaet(n: int) -> int:
|
||||
"""Berechnet n! (Fakultät von n)."""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schreibe die Funktion "zaehle_gerade_zahlen(start: int, ende: int) -> int".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Zählt, wie viele gerade Zahlen im Intervall von start bis ende (beide inklusive!)
|
||||
# liegen.
|
||||
#
|
||||
# Beispiele:
|
||||
# - zaehle_gerade_zahlen(1, 6) -> 3 (nämlich 2, 4, 6)
|
||||
# - zaehle_gerade_zahlen(2, 4) -> 2 (nämlich 2, 4)
|
||||
# - zaehle_gerade_zahlen(5, 5) -> 0
|
||||
# - zaehle_gerade_zahlen(10, 2) -> 0 (wenn start > ende)
|
||||
#
|
||||
# Tipp:
|
||||
# Eine Zahl x ist gerade, wenn x % 2 == 0 gilt.
|
||||
# Nutze eine for-Schleife über range(start, ende + 1) und zähle mit zaehler += 1.
|
||||
# ==============================================================================
|
||||
|
||||
def zaehle_gerade_zahlen(start: int, ende: int) -> int:
|
||||
"""Zählt alle geraden Zahlen im Bereich [start, ende]."""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Schreibe die Funktion "ist_primzahl(n: int) -> bool".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Eine Primzahl ist eine ganze Zahl größer als 1, die nur durch 1 und sich selbst
|
||||
# ohne Rest teilbar ist (z.B. 2, 3, 5, 7, 11, 13, ...).
|
||||
#
|
||||
# Regeln:
|
||||
# - Zahlen kleiner oder gleich 1 (n <= 1) sind KEINE Primzahlen -> False.
|
||||
# - Die Zahl 2 ist die kleinste Primzahl -> True.
|
||||
# - Prüfe mit einer for-Schleife alle möglichen Teiler i von 2 bis n - 1
|
||||
# (oder bis int(n**0.5) + 1):
|
||||
# Wenn n durch i ohne Rest teilbar ist (n % i == 0), dann ist n KEINE Primzahl
|
||||
# -> brich sofort ab und gib False zurück!
|
||||
# - Wird kein Teiler gefunden, gib am Ende True zurück.
|
||||
# ==============================================================================
|
||||
|
||||
def ist_primzahl(n: int) -> bool:
|
||||
"""Prüft, ob n eine Primzahl ist."""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 5: Schreibe die Funktion "quorsumme(n: int) -> int".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Berechnet die Quersumme einer Zahl n mittels einer WHILE-Schleife.
|
||||
# Die Quersumme ist die Summe aller einzelnen Ziffern der Zahl.
|
||||
#
|
||||
# Beispiele:
|
||||
# - quorsumme(482) = 4 + 8 + 2 = 14
|
||||
# - quorsumme(1234) = 1 + 2 + 3 + 4 = 10
|
||||
# - quorsumme(0) = 0
|
||||
# - quorsumme(-482) = 14 (behandle negative Zahlen mit abs(n))
|
||||
#
|
||||
# Wie holt man Ziffern mit while heraus? (Klassischer Algorithmus):
|
||||
# 1. Zahl positiv machen: rest = abs(n), summe = 0
|
||||
# 2. while rest > 0:
|
||||
# letzte_ziffer = rest % 10 # Modulo 10 liefert die letzte Ziffer
|
||||
# summe += letzte_ziffer
|
||||
# rest = rest // 10 # Ganzzahldivision schneidet letzte Ziffer ab
|
||||
# 3. summe zurückgeben!
|
||||
# ==============================================================================
|
||||
|
||||
def quorsumme(n: int) -> int:
|
||||
"""Berechnet die Quersumme von n mittels einer while-Schleife."""
|
||||
# Schreibe hier deinen Code für TODO 5:
|
||||
pass
|
||||
|
||||
|
||||
# Alias für deutsche Schreibweise
|
||||
quersumme = quorsumme
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum manuellen Ausprobieren:
|
||||
# (Führe diese Datei aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 50)
|
||||
print("🎡 KAPITEL G05: SCHLEIFEN & WIEDERHOLUNGEN")
|
||||
print("=" * 50)
|
||||
|
||||
# 1. Summe
|
||||
s5 = summe_bis(5)
|
||||
print(f"Summe von 1 bis 5: {s5} (Erwartet: 15)")
|
||||
|
||||
# 2. Fakultät
|
||||
f5 = fakultaet(5)
|
||||
print(f"Fakultät von 5 (5!): {f5} (Erwartet: 120)")
|
||||
|
||||
# 3. Gerade Zahlen zählen
|
||||
g = zaehle_gerade_zahlen(1, 10)
|
||||
print(f"Gerade Zahlen von 1 bis 10: {g} (Erwartet: 5)")
|
||||
|
||||
# 4. Primzahlprüfung
|
||||
p7 = ist_primzahl(7)
|
||||
p9 = ist_primzahl(9)
|
||||
print(f"Ist 7 eine Primzahl? {p7} (Erwartet: True)")
|
||||
print(f"Ist 9 eine Primzahl? {p9} (Erwartet: False)")
|
||||
|
||||
# 5. Quersumme
|
||||
q = quorsumme(482)
|
||||
print(f"Quersumme von 482: {q} (Erwartet: 14)")
|
||||
print("=" * 50)
|
||||
print("💡 Führe 'python3 test_aufgabe.py' aus, um deine Lösungen zu prüfen!")
|
||||
332
g05_schleifen_und_wiederholungen/index.html
Normal file
332
g05_schleifen_und_wiederholungen/index.html
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G05: Schleifen & Wiederholungen</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g04_verzweigungen_und_bedingungen/index.html">← Kapitel G04</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G05</span>
|
||||
<span>›</span>
|
||||
<a href="../g06_funktionen_und_module/index.html">Kapitel G06 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G05 • Schulabgleich 09.1 & 09.2</div>
|
||||
<h1>Schleifen & Wiederholungen 🎡🔄</h1>
|
||||
<p>Lerne Zählschleifen (for), Bedingungsschleifen (while), Schleifen-Akkumulatoren und die Steuerbefehle break & continue kennen.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie & Grundkonzept -->
|
||||
<section class="card">
|
||||
<h2>1. Die Grundidee: Warum brauchen wir Schleifen?</h2>
|
||||
|
||||
<p>
|
||||
Computer sind unschlagbar schnell darin, monotone Aufgaben millionenfach zu wiederholen. Anstatt 100-mal denselben Befehl untereinander zu schreiben, sagen wir Python einfach: <em>"Wiederhole diesen Code-Block X-mal!"</em>
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🎡 Die Karussell- & Riesenrad-Analogie:</div>
|
||||
<p>Es gibt in Python zwei Hauptarten von Schleifen:</p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li><strong>Zählschleife (<code>for</code>):</strong> Wie ein <strong>Karussell mit Wertmarken</strong>. Du kaufst 5 Runden. Der Automat zählt: 1, 2, 3, 4, 5 – und stoppt genau nach 5 Runden.</li>
|
||||
<li><strong>Bedingungsschleife (<code>while</code>):</strong> Wie ein <strong>Riesenrad, das sich dreht, SOLANGE die Musik spielt</strong>. Sobald die Musik stoppt (Bedingung wird <code>False</code>), hält das Rad an.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Zählschleifen & range() -->
|
||||
<section class="card">
|
||||
<h2>2. Zählschleifen: <code>for</code> und <code>range()</code></h2>
|
||||
|
||||
<p>
|
||||
Verwende <code>for</code>, wenn du im Voraus weißt, <strong>wie oft</strong> etwas wiederholt werden soll. Die Funktion <code>range()</code> erzeugt dafür die Zahlenfolge.
|
||||
</p>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Die goldene range()-Regel: Der Stop-Wert ist immer EXKLUSIV!</div>
|
||||
<code>range(1, 5)</code> läuft von <strong>1 bis 4</strong> (die Zahl 5 ist <strong>nicht</strong> dabei)!<br>
|
||||
Wenn du bis 5 zählen willst, musst du <code>range(1, 6)</code> schreiben.
|
||||
</div>
|
||||
|
||||
<h3>Die 3 Varianten von <code>range()</code> im Überblick:</h3>
|
||||
<div style="overflow-x: auto; margin: 15px 0;">
|
||||
<table style="width: 100%; border-collapse: collapse; background: white; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border-color);">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light); color: var(--primary); text-align: left;">
|
||||
<th style="padding: 10px 14px; border-bottom: 2px solid var(--border-color);">Aufruf</th>
|
||||
<th style="padding: 10px 14px; border-bottom: 2px solid var(--border-color);">Bedeutung</th>
|
||||
<th style="padding: 10px 14px; border-bottom: 2px solid var(--border-color);">Erzeugte Zahlen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);"><code>range(5)</code></td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);">Start bei 0 bis Stop-1</td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color); font-weight: bold; color: var(--primary);">0, 1, 2, 3, 4</td>
|
||||
</tr>
|
||||
<tr style="background: #f8fafc;">
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);"><code>range(1, 6)</code></td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);">Start bei 1 bis 6-1</td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color); font-weight: bold; color: var(--primary);">1, 2, 3, 4, 5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);"><code>range(0, 10, 2)</code></td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color);">Start bei 0, 2er-Schritte</td>
|
||||
<td style="padding: 10px 14px; border-bottom: 1px solid var(--border-color); font-weight: bold; color: var(--primary);">0, 2, 4, 6, 8</td>
|
||||
</tr>
|
||||
<tr style="background: #f8fafc;">
|
||||
<td style="padding: 10px 14px;"><code>range(5, 0, -1)</code></td>
|
||||
<td style="padding: 10px 14px;">Rückwärts (Countdown!)</td>
|
||||
<td style="padding: 10px 14px; font-weight: bold; color: var(--primary);">5, 4, 3, 2, 1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python (for-Schleife mit range)</span>
|
||||
</div>
|
||||
<pre><span class="cm"># Countdown von 5 bis 1</span>
|
||||
<span class="kw">for</span> <span class="var">sekunde</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">5</span>, <span class="num">0</span>, <span class="num">-1</span>):
|
||||
<span class="fn">print</span>(<span class="str">f"Raketenstart in {sekunde}..."</span>)
|
||||
<span class="fn">print</span>(<span class="str">"🚀 Liftoff!"</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Bedingungsschleifen & Endlosschleifen -->
|
||||
<section class="card">
|
||||
<h2>3. Bedingungsschleifen: <code>while</code></h2>
|
||||
|
||||
<p>
|
||||
Verwende <code>while</code>, wenn du nicht weißt, wie viele Durchläufe nötig sind, sondern die Schleife laufen soll, <strong>solange eine Bedingung wahr (<code>True</code>) ist</strong>.
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots"><span class="code-dot dot-red"></span><span class="code-dot dot-yellow"></span><span class="code-dot dot-green"></span></div>
|
||||
<span>Python (while-Schleife)</span>
|
||||
</div>
|
||||
<pre><span class="var">energie</span> = <span class="num">3</span>
|
||||
<span class="kw">while</span> <span class="var">energie</span> > <span class="num">0</span>:
|
||||
<span class="fn">print</span>(<span class="str">f"Roboter läuft... Energie: {energie}"</span>)
|
||||
<span class="var">energie</span> -= <span class="num">1</span> <span class="cm"># ⚠️ Zähler anpassen, sonst Endlosschleife!</span>
|
||||
|
||||
<span class="fn">print</span>(<span class="str">"Akku leer! Bitte aufladen."</span>)</pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-danger">
|
||||
<div class="box-title">🛑 Achtung vor der Endlosschleife (Infinite Loop)!</div>
|
||||
<p>Wenn die Bedingung niemals <code>False</code> wird, stürzt dein Programm zwar nicht ab, aber es friert für immer ein! Verändere immer die Prüfvariable im Schleifenkörper.</p>
|
||||
<p style="margin-top: 8px;"><strong>Notausstieg im Terminal:</strong> Drücke <kbd>Strg</kbd> + <kbd>C</kbd>, um eine Endlosschleife sofort abzubrechen!</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Schleifen steuern: break & continue -->
|
||||
<section class="card">
|
||||
<h2>4. Schleifen-Steuerung: <code>break</code> & <code>continue</code></h2>
|
||||
|
||||
<p>Mit zwei speziellen Schlüsselwörtern hast du volle Kontrolle über den Schleifenablauf:</p>
|
||||
|
||||
<div class="extension-grid">
|
||||
<div class="extension-card">
|
||||
<div class="extension-icon" style="background: var(--danger-light); color: var(--danger);">🛑</div>
|
||||
<div class="extension-info">
|
||||
<h4><code>break</code> (Notbremse)</h4>
|
||||
<p>Beendet die Schleife <strong>sofort und vollständig</strong>. Die Programmausführung springt direkt hinter die Schleife.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="extension-card">
|
||||
<div class="extension-icon" style="background: var(--warning-light); color: var(--warning);">⏭️</div>
|
||||
<div class="extension-info">
|
||||
<h4><code>continue</code> (Nächste Runde)</h4>
|
||||
<p>Bricht nur die <strong>aktuelle Runde</strong> ab und springt sofort zum nächsten Schleifendurchlauf.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots"><span class="code-dot dot-red"></span><span class="code-dot dot-yellow"></span><span class="code-dot dot-green"></span></div>
|
||||
<span>Python (break und continue im Einsatz)</span>
|
||||
</div>
|
||||
<pre><span class="cm"># Beispiel: Nur ungerade Zahlen drucken, bei 7 abbrechen</span>
|
||||
<span class="kw">for</span> <span class="var">zahl</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="num">11</span>):
|
||||
<span class="kw">if</span> <span class="var">zahl</span> % <span class="num">2</span> == <span class="num">0</span>:
|
||||
<span class="kw">continue</span> <span class="cm"># Überspringe gerade Zahlen</span>
|
||||
<span class="kw">if</span> <span class="var">zahl</span> == <span class="num">7</span>:
|
||||
<span class="fn">print</span>(<span class="str">"Glückszahl 7 gefunden -> Abbruch!"</span>)
|
||||
<span class="kw">break</span> <span class="cm"># Schleife komplett beenden</span>
|
||||
<span class="fn">print</span>(<span class="str">"Ungerade Zahl:"</span>, <span class="var">zahl</span>)
|
||||
|
||||
<span class="cm"># Ausgabe: 1, 3, 5, danach Abbruch!</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Schleifen-Akkumulator Muster -->
|
||||
<section class="card">
|
||||
<h2>5. Das Akkumulator-Muster 🧺</h2>
|
||||
|
||||
<p>
|
||||
Ein <strong>Akkumulator</strong> (Sammelbehälter) ist eines der wichtigsten Entwurfsmuster der Informatik. Er sammelt während der Schleife Werte an:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots"><span class="code-dot dot-red"></span><span class="code-dot dot-yellow"></span><span class="code-dot dot-green"></span></div>
|
||||
<span>Python (Die 3 klassischen Akkumulatoren)</span>
|
||||
</div>
|
||||
<pre><span class="cm"># 1. Summen-Akkumulator (Startwert: 0)</span>
|
||||
<span class="var">summe</span> = <span class="num">0</span>
|
||||
<span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> [<span class="num">10</span>, <span class="num">20</span>, <span class="num">30</span>]:
|
||||
<span class="var">summe</span> += <span class="var">x</span> <span class="cm"># summe = summe + x</span>
|
||||
<span class="fn">print</span>(<span class="str">"Gesamtsumme:"</span>, <span class="var">summe</span>) <span class="cm"># 60</span>
|
||||
|
||||
<span class="cm"># 2. Zähler-Akkumulator (Startwert: 0)</span>
|
||||
<span class="var">anzahl</span> = <span class="num">0</span>
|
||||
<span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="num">11</span>):
|
||||
<span class="kw">if</span> <span class="var">x</span> % <span class="num">2</span> == <span class="num">0</span>:
|
||||
<span class="var">anzahl</span> += <span class="num">1</span>
|
||||
<span class="fn">print</span>(<span class="str">"Anzahl gerade Zahlen:"</span>, <span class="var">anzahl</span>) <span class="cm"># 5</span>
|
||||
|
||||
<span class="cm"># 3. Produkt-Akkumulator (Startwert: 1, NIEMALS 0!)</span>
|
||||
<span class="var">produkt</span> = <span class="num">1</span>
|
||||
<span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="num">5</span>):
|
||||
<span class="var">produkt</span> *= <span class="var">x</span> <span class="cm"># 1 * 2 * 3 * 4</span>
|
||||
<span class="fn">print</span>(<span class="str">"Produkt (4!):"</span>, <span class="var">produkt</span>) <span class="cm"># 24</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">💡 Goldene Akkumulator-Regel:</div>
|
||||
Definiere die Akkumulator-Variable (<code>summe = 0</code> oder <code>produkt = 1</code>) <strong>immer VOR</strong> der Schleife! Wenn du sie in der Schleife definierst, wird der Wert bei jedem Durchlauf wieder auf 0 bzw. 1 zurückgesetzt.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. Aufgaben & Checkliste -->
|
||||
<section class="card">
|
||||
<h2>6. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g05_schleifen_und_wiederholungen/aufgabe.py</code> und bearbeite die folgenden 5 Funktionen:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>summe_bis(n: int) -> int</code></strong><br>
|
||||
Berechnet $1 + 2 + \dots + n$ mit einer <code>for</code>-Schleife und <code>range(1, n + 1)</code>. Gibt 0 zurück, falls $n \le 0$.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>fakultaet(n: int) -> int</code></strong><br>
|
||||
Berechnet $n! = 1 \cdot 2 \dots n$. Für $n = 0$ ist das Ergebnis 1. Bei $n < 0$ wird ein <code>ValueError</code> ausgelöst.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>zaehle_gerade_zahlen(start: int, ende: int) -> int</code></strong><br>
|
||||
Zählt alle geraden Zahlen im Bereich von <code>start</code> bis <code>ende</code> (inklusive). Gibt 0 zurück, wenn <code>start > ende</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>ist_primzahl(n: int) -> bool</code></strong><br>
|
||||
Prüft, ob <code>n</code> eine Primzahl ist. Gibt <code>False</code> zurück für $n \le 1$, <code>True</code> für 2, und bricht mit <code>return False</code> ab, sobald ein Teiler gefunden wird.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5">
|
||||
<label for="t5" class="task-label">
|
||||
<strong>TODO 5: <code>quorsumme(n: int) -> int</code></strong><br>
|
||||
Berechnet die Quersumme einer Zahl mit einer <code>while</code>-Schleife durch wiederholtes <code>rest % 10</code> und <code>rest //= 10</code>.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 1 & 2 (Summe & Fakultät)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">summe_bis</span>(<span class="var">n</span>: <span class="fn">int</span>) -> <span class="fn">int</span>:
|
||||
<span class="kw">if</span> <span class="var">n</span> <= <span class="num">0</span>:
|
||||
<span class="kw">return</span> <span class="num">0</span>
|
||||
<span class="var">summe</span> = <span class="num">0</span>
|
||||
<span class="kw">for</span> <span class="var">i</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="var">n</span> + <span class="num">1</span>):
|
||||
<span class="var">summe</span> += <span class="var">i</span>
|
||||
<span class="kw">return</span> <span class="var">summe</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 4 (Primzahl-Test mit Schleife)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">ist_primzahl</span>(<span class="var">n</span>: <span class="fn">int</span>) -> <span class="fn">bool</span>:
|
||||
<span class="kw">if</span> <span class="var">n</span> <= <span class="num">1</span>:
|
||||
<span class="kw">return</span> <span class="kw">False</span>
|
||||
<span class="kw">for</span> <span class="var">i</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">2</span>, <span class="var">n</span>):
|
||||
<span class="kw">if</span> <span class="var">n</span> % <span class="var">i</span> == <span class="num">0</span>:
|
||||
<span class="kw">return</span> <span class="kw">False</span> <span class="cm"># Teiler gefunden -> keine Primzahl!</span>
|
||||
<span class="kw">return</span> <span class="kw">True</span> <span class="cm"># Kein Teiler gefunden -> Primzahl!</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 5 (Quersumme mit while-Schleife)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">quorsumme</span>(<span class="var">n</span>: <span class="fn">int</span>) -> <span class="fn">int</span>:
|
||||
<span class="var">rest</span> = <span class="fn">abs</span>(<span class="var">n</span>)
|
||||
<span class="var">summe</span> = <span class="num">0</span>
|
||||
<span class="kw">while</span> <span class="var">rest</span> > <span class="num">0</span>:
|
||||
<span class="var">summe</span> += <span class="var">rest</span> % <span class="num">10</span> <span class="cm"># Letzte Ziffer addieren</span>
|
||||
<span class="var">rest</span> = <span class="var">rest</span> // <span class="num">10</span> <span class="cm"># Letzte Ziffer abschneiden</span>
|
||||
<span class="kw">return</span> <span class="var">summe</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 7. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>7. 🧪 Testen & Weitergehen</h2>
|
||||
<p>Führe im Terminal den Unittest aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g04_verzweigungen_und_bedingungen/index.html" class="btn btn-secondary">← Zurück zu Kapitel G04</a>
|
||||
<a href="../g06_funktionen_und_module/index.html" class="btn">Weiter zu Kapitel G06 (Funktionen & Module) →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
77
g05_schleifen_und_wiederholungen/musterloesung.py
Normal file
77
g05_schleifen_und_wiederholungen/musterloesung.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
"""
|
||||
Kapitel G05: Schleifen & Wiederholungen – Musterlösung
|
||||
=====================================================
|
||||
Schulabgleich: 09.1 & 09.2
|
||||
"""
|
||||
|
||||
|
||||
def summe_bis(n: int) -> int:
|
||||
"""Berechnet 1 + 2 + ... + n."""
|
||||
if n <= 0:
|
||||
return 0
|
||||
summe = 0
|
||||
for i in range(1, n + 1):
|
||||
summe += i
|
||||
return summe
|
||||
|
||||
|
||||
def fakultaet(n: int) -> int:
|
||||
"""Berechnet n! (Fakultät von n)."""
|
||||
if n < 0:
|
||||
raise ValueError("Fakultät ist für negative Zahlen nicht definiert")
|
||||
if n == 0:
|
||||
return 1
|
||||
produkt = 1
|
||||
for i in range(1, n + 1):
|
||||
produkt *= i
|
||||
return produkt
|
||||
|
||||
|
||||
def zaehle_gerade_zahlen(start: int, ende: int) -> int:
|
||||
"""Zählt alle geraden Zahlen im Bereich [start, ende]."""
|
||||
if start > ende:
|
||||
return 0
|
||||
zaehler = 0
|
||||
for zahl in range(start, ende + 1):
|
||||
if zahl % 2 == 0:
|
||||
zaehler += 1
|
||||
return zaehler
|
||||
|
||||
|
||||
def ist_primzahl(n: int) -> bool:
|
||||
"""Prüft, ob n eine Primzahl ist."""
|
||||
if n <= 1:
|
||||
return False
|
||||
if n == 2:
|
||||
return True
|
||||
if n % 2 == 0:
|
||||
return False
|
||||
# Prüfe ungerade Teiler bis zur Wurzel von n
|
||||
for teiler in range(3, int(n**0.5) + 1, 2):
|
||||
if n % teiler == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def quorsumme(n: int) -> int:
|
||||
"""Berechnet die Quersumme von n mittels einer while-Schleife."""
|
||||
rest = abs(n)
|
||||
summe = 0
|
||||
while rest > 0:
|
||||
letzte_ziffer = rest % 10
|
||||
summe += letzte_ziffer
|
||||
rest = rest // 10
|
||||
return summe
|
||||
|
||||
|
||||
# Alias für alternative Schreibweise
|
||||
quersumme = quorsumme
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Musterlösung G05 Demonstrationen:")
|
||||
print("summe_bis(5) =", summe_bis(5))
|
||||
print("fakultaet(5) =", fakultaet(5))
|
||||
print("zaehle_gerade_zahlen(1, 10) =", zaehle_gerade_zahlen(1, 10))
|
||||
print("ist_primzahl(17) =", ist_primzahl(17))
|
||||
print("quorsumme(482) =", quorsumme(482))
|
||||
178
g05_schleifen_und_wiederholungen/test_aufgabe.py
Normal file
178
g05_schleifen_und_wiederholungen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
"""
|
||||
Testsuite für Kapitel G05: Schleifen & Wiederholungen
|
||||
=====================================================
|
||||
Schulabgleich: 09.1 & 09.2
|
||||
"""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das aktuelle Verzeichnis im Modulpfad ist
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG05(unittest.TestCase):
|
||||
|
||||
def test_01_summe_bis(self):
|
||||
"""Prüft die Funktion summe_bis(n)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "summe_bis"),
|
||||
"Fehler: Die Funktion 'summe_bis' fehlt in aufgabe.py!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(1), 1,
|
||||
"Fehler: summe_bis(1) sollte 1 ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(5), 15,
|
||||
"Fehler: summe_bis(5) sollte 15 (1+2+3+4+5) ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(10), 55,
|
||||
"Fehler: summe_bis(10) sollte 55 ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(100), 5050,
|
||||
"Fehler: summe_bis(100) sollte 5050 (Gaußsche Summenformel) ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(0), 0,
|
||||
"Fehler: summe_bis(0) sollte 0 zurückgeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.summe_bis(-10), 0,
|
||||
"Fehler: summe_bis für negative Zahlen sollte 0 zurückgeben!"
|
||||
)
|
||||
|
||||
def test_02_fakultaet(self):
|
||||
"""Prüft die Funktion fakultaet(n)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "fakultaet"),
|
||||
"Fehler: Die Funktion 'fakultaet' fehlt in aufgabe.py!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.fakultaet(0), 1,
|
||||
"Fehler: fakultaet(0) ist mathematisch 1 (0! = 1)!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.fakultaet(1), 1,
|
||||
"Fehler: fakultaet(1) sollte 1 ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.fakultaet(4), 24,
|
||||
"Fehler: fakultaet(4) sollte 24 (1*2*3*4) ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.fakultaet(5), 120,
|
||||
"Fehler: fakultaet(5) sollte 120 ergeben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.fakultaet(7), 5040,
|
||||
"Fehler: fakultaet(7) sollte 5040 ergeben!"
|
||||
)
|
||||
# Fehlerbehandlung bei negativen Zahlen
|
||||
with self.assertRaises(ValueError, msg="Fehler: fakultaet(-1) muss einen ValueError auslösen!"):
|
||||
aufgabe.fakultaet(-1)
|
||||
with self.assertRaises(ValueError, msg="Fehler: fakultaet(-5) muss einen ValueError auslösen!"):
|
||||
aufgabe.fakultaet(-5)
|
||||
|
||||
def test_03_zaehle_gerade_zahlen(self):
|
||||
"""Prüft die Funktion zaehle_gerade_zahlen(start, ende)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "zaehle_gerade_zahlen"),
|
||||
"Fehler: Die Funktion 'zaehle_gerade_zahlen' fehlt in aufgabe.py!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(1, 6), 3,
|
||||
"Fehler: Im Bereich von 1 bis 6 gibt es 3 gerade Zahlen (2, 4, 6)!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(1, 10), 5,
|
||||
"Fehler: Im Bereich von 1 bis 10 gibt es 5 gerade Zahlen (2, 4, 6, 8, 10)!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(2, 4), 2,
|
||||
"Fehler: Im Bereich von 2 bis 4 gibt es 2 gerade Zahlen (2, 4)!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(3, 3), 0,
|
||||
"Fehler: 3 ist ungerade, also sollte 0 zurückgegeben werden!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(4, 4), 1,
|
||||
"Fehler: Im Bereich [4, 4] gibt es genau eine gerade Zahl (4)!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(10, 5), 0,
|
||||
"Fehler: Wenn start > ende ist, sollte 0 zurückgegeben werden!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_gerade_zahlen(-4, 2), 4,
|
||||
"Fehler: Im Bereich [-4, 2] liegen -4, -2, 0, 2 (4 gerade Zahlen)!"
|
||||
)
|
||||
|
||||
def test_04_ist_primzahl(self):
|
||||
"""Prüft die Funktion ist_primzahl(n)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "ist_primzahl"),
|
||||
"Fehler: Die Funktion 'ist_primzahl' fehlt in aufgabe.py!"
|
||||
)
|
||||
# Echte Primzahlen
|
||||
for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 97]:
|
||||
self.assertTrue(
|
||||
aufgabe.ist_primzahl(p),
|
||||
f"Fehler: {p} ist eine Primzahl, wurde aber als False bewertet!"
|
||||
)
|
||||
|
||||
# Keine Primzahlen
|
||||
for non_p in [0, 1, -1, -7, 4, 6, 8, 9, 15, 21, 25, 100]:
|
||||
self.assertFalse(
|
||||
aufgabe.ist_primzahl(non_p),
|
||||
f"Fehler: {non_p} ist KEINE Primzahl, wurde aber als True bewertet!"
|
||||
)
|
||||
|
||||
def test_05_quorsumme(self):
|
||||
"""Prüft die Funktion quorsumme(n)."""
|
||||
fn = getattr(aufgabe, "quorsumme", getattr(aufgabe, "quersumme", None))
|
||||
self.assertIsNotNone(
|
||||
fn,
|
||||
"Fehler: Die Funktion 'quorsumme' (oder 'quersumme') fehlt in aufgabe.py!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(0), 0,
|
||||
"Fehler: Quersumme von 0 sollte 0 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(5), 5,
|
||||
"Fehler: Quersumme von 5 sollte 5 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(123), 6,
|
||||
"Fehler: Quersumme von 123 (1+2+3) sollte 6 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(482), 14,
|
||||
"Fehler: Quersumme von 482 (4+8+2) sollte 14 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(9999), 36,
|
||||
"Fehler: Quersumme von 9999 (9+9+9+9) sollte 36 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(1000), 1,
|
||||
"Fehler: Quersumme von 1000 sollte 1 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
fn(-482), 14,
|
||||
"Fehler: Quersumme von -482 sollte 14 sein (Vorzeichen wird ignoriert)!"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
169
g06_funktionen_und_module/README.md
Normal file
169
g06_funktionen_und_module/README.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
# Kapitel G06: Eigene Funktionen & Module 🪄📦
|
||||
|
||||
Willkommen zu **Kapitel G06** unseres Python-Grundlagen-Lehrpfads!
|
||||
Dieses Kapitel entspricht den Modulen **05.0 & 05.1** deines Informatik-Skriptums.
|
||||
|
||||
Bis jetzt hast du vorgefertigte Funktionen wie `print()`, `len()` oder `range()` genutzt. Jetzt lernst du, wie du **deine eigenen Funktionen schreibst** und mächtige **Module der Standardbibliothek** (wie `math` und `random`) einbindest.
|
||||
|
||||
---
|
||||
|
||||
## 🪄 Die Fabrik- / Zauberkisten-Analogie
|
||||
|
||||
Stell dir eine Funktion wie eine kleine Fabrikmaschine (oder einen Zauberkasten) vor:
|
||||
|
||||
```
|
||||
[ INPUT / ZUTATEN ]
|
||||
(Parameter: z.B. a=3, b=4)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────┐
|
||||
│ EIGENE FUNKTION │
|
||||
│ def hypotenuse(a, b): │ <─── VERARBEITUNG (Black Box)
|
||||
│ c = math.sqrt(...) │
|
||||
└────────────┬────────────┘
|
||||
│
|
||||
▼
|
||||
[ OUTPUT / PRODUKT ]
|
||||
(return 5.0)
|
||||
```
|
||||
|
||||
1. **Input (Parameter):** Was die Funktion braucht, um zu arbeiten (z.B. zwei Zahlen).
|
||||
2. **Verarbeitung:** Der Code innerhalb der Funktion, der die Berechnung durchführt.
|
||||
3. **Output (`return`):** Das fertige Ergebnis, das die Funktion an den Aufrufer zurückgibt.
|
||||
|
||||
---
|
||||
|
||||
## 1. Funktionen definieren: `def` & Standardwerte
|
||||
|
||||
```python
|
||||
# Definition mit Parametern und Standardwert (Default Argument):
|
||||
def begruesse(name: str, titel: str = "Frau/Herr") -> str:
|
||||
return f"Guten Tag, {titel} {name}!"
|
||||
|
||||
# Aufruf mit beiden Argumenten:
|
||||
print(begruesse("Müller", "Dr.")) # "Guten Tag, Dr. Müller!"
|
||||
|
||||
# Aufruf ohne Standardwert (nimmt Default "Frau/Herr"):
|
||||
print(begruesse("Schmidt")) # "Guten Tag, Frau/Herr Schmidt!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Der fundamentale Unterschied: `return` vs. `print()`
|
||||
|
||||
Das ist der mit Abstand häufigste Anfängerfehler:
|
||||
|
||||
| Eigenschaft | `print()` 🖨️ | `return` 📦 |
|
||||
| :--- | :--- | :--- |
|
||||
| **Was passiert?** | Schreibt nur Text auf den Bildschirm. | Übergibt das echte Ergebnis zurück an das Programm. |
|
||||
| **Weiterverwendung?** | **NEIN!** Das Ergebnis ist für das Programm verloren (`None`). | **JA!** Du kannst das Ergebnis in Variablen speichern, weiterrechnen oder vergleichen. |
|
||||
| **Analogie:** | Du liest den Kassenzettel im Supermarkt. | Du nimmst die gekaufte Ware mit nach Hause! |
|
||||
|
||||
```python
|
||||
# ❌ Falsch: Mit print kann man nicht weiterrechnen!
|
||||
def verdopple_falsch(x):
|
||||
print(x * 2)
|
||||
|
||||
ergebnis = verdopple_falsch(5) # Gibt 10 auf dem Bildschirm aus
|
||||
# print(ergebnis + 5) # 💥 TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'!
|
||||
|
||||
# ✅ Richtig: Mit return kann man das Ergebnis weiterverwenden!
|
||||
def verdopple_richtig(x):
|
||||
return x * 2
|
||||
|
||||
ergebnis = verdopple_richtig(5) # ergebnis ist jetzt 10
|
||||
print(ergebnis + 5) # Funktioniert perfekt -> 15!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Mehrere Rückgabewerte (Tupel-Return)
|
||||
|
||||
In Python kann eine Funktion problemlos **mehrere Werte gleichzeitig** zurückgeben. Python packt sie automatisch in ein **Tupel**:
|
||||
|
||||
```python
|
||||
def min_und_max(zahlen: list[float]) -> tuple[float, float]:
|
||||
kleinste = min(zahlen)
|
||||
groesste = max(zahlen)
|
||||
return kleinste, groesste # Gibt (kleinste, groesste) zurück
|
||||
|
||||
# Tuple-Unpacking (Entpacken in zwei separate Variablen):
|
||||
tiefst, hoechst = min_und_max([12.5, 3.2, 19.8, -1.0])
|
||||
print(f"Tiefstwert: {tiefst}, Höchstwert: {hoechst}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Lokaler vs. Globaler Gültigkeitsbereich (Scope) 🏠
|
||||
|
||||
Variablen, die du **innerhalb** einer Funktion erstellst, sind **lokal**. Sie existieren nur so lange, wie die Funktion ausgeführt wird:
|
||||
|
||||
```python
|
||||
def meine_funktion():
|
||||
geheime_zahl = 42 # Lokale Variable!
|
||||
print("In der Funktion:", geheime_zahl)
|
||||
|
||||
meine_funktion()
|
||||
# print(geheime_zahl) # 💥 NameError: name 'geheime_zahl' is not defined!
|
||||
```
|
||||
|
||||
> **Die Hotelzimmer-Regel:** Was im Hotelzimmer (der Funktion) liegt, sieht man von außen auf der Straße nicht.
|
||||
|
||||
---
|
||||
|
||||
## 5. Module nutzen: `math` & `random` 🧰
|
||||
|
||||
Python hat eine riesige "Werkzeugkiste" an eingebauten Modulen (Standard Library), die du einfach mit `import` laden kannst:
|
||||
|
||||
### Das `math`-Modul (Mathematische Werkzeuge):
|
||||
```python
|
||||
import math
|
||||
|
||||
print(math.sqrt(25)) # Quadratwurzel -> 5.0
|
||||
print(math.pi) # Kreiszahl Pi -> 3.141592653589793
|
||||
print(math.pow(2, 3)) # Potenz 2^3 -> 8.0
|
||||
print(math.floor(4.9)) # Abrunden -> 4
|
||||
print(math.ceil(4.1)) # Aufrunden -> 5
|
||||
```
|
||||
|
||||
### Das `random`-Modul (Zufallszahlen & Würfel):
|
||||
```python
|
||||
import random
|
||||
|
||||
# Zufällige ganze Zahl zwischen 1 und 6 (beide inklusive):
|
||||
wuerfelwurf = random.randint(1, 6)
|
||||
|
||||
# Zufällige Kommazahl zwischen 0.0 und 1.0:
|
||||
zufall = random.random()
|
||||
|
||||
# Zufälliges Element aus einer Liste wählen:
|
||||
farben = ["rot", "grün", "blau", "gelb"]
|
||||
gluecksfarbe = random.choice(farben)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Die 3 häufigsten Anfängerfehler
|
||||
|
||||
1. **`return` vergessen oder durch `print()` ersetzt:**
|
||||
- Deine Funktion berechnet etwas, gibt es aber nicht an den Aufrufer zurück. Ergebnis ist `None`.
|
||||
2. **Auf lokale Variablen von außen zugreifen:**
|
||||
- Variablen innerhalb von Funktionen existieren außerhalb nicht.
|
||||
3. **Falsche Modul-Namen oder Funktionen:**
|
||||
- Achte auf die Schreibweise: `math.sqrt()` (nicht `math.square_root()`) und `random.randint(1, 6)` (nicht `random.random_int()`).
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `aufgabe.py` und bearbeite die nummerierten TODOs:
|
||||
1. **TODO 1:** `hypotenuse(a: float, b: float) -> float` – Satz des Pythagoras mit `math.sqrt`.
|
||||
2. **TODO 2:** `zylinder_volumen(radius: float, hoehe: float) -> float` – Zylindervolumen mit `math.pi`.
|
||||
3. **TODO 3:** `wuerfle_wuerfel(anzahl: int, seiten: int = 6) -> list[int]` – Würfelsimulator mit `random.randint` und Standardwert `seiten=6`.
|
||||
4. **TODO 4:** `statistik(zahlen: list[float]) -> tuple[float, float, float]` – Berechnet `(min, max, mittelwert)` als Tupel.
|
||||
|
||||
### Testen:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
Sobald alle 7 Tests erfolgreich durchlaufen (`OK`), hast du Funktionen und Module gemeistert!
|
||||
145
g06_funktionen_und_module/aufgabe.py
Normal file
145
g06_funktionen_und_module/aufgabe.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""
|
||||
Kapitel G06: Eigene Funktionen & Module – Aufgabenblatt
|
||||
======================================================
|
||||
Schulabgleich: 05.0 & 05.1
|
||||
|
||||
In diesem Kapitel lernst du:
|
||||
- Eigene Funktionen mit Parametern und Standardwerten definieren (def)
|
||||
- Rückgabewerte mit 'return' (und warum 'return' nicht 'print' ist!)
|
||||
- Mehrere Rückgabewerte als Tupel zurückgeben (Tuple-Return)
|
||||
- Lokale vs. Globale Gültigkeit von Variablen (Scope)
|
||||
- Standardbibliotheks-Module importieren und nutzen (math, random)
|
||||
|
||||
Bearbeite die Aufgaben von TODO 1 bis TODO 4.
|
||||
Teste deine Lösungen jederzeit im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
# ==============================================================================
|
||||
# Modul-Importe:
|
||||
# Importiere hier die benötigten Standard-Module (math und random):
|
||||
# ==============================================================================
|
||||
import math
|
||||
import random
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Schreibe die Funktion "hypotenuse(a: float, b: float) -> float".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Berechnet die Länge der Hypotenuse c eines rechtwinkligen Dreiecks nach dem
|
||||
# Satz des Pythagoras: c = sqrt(a² + b²).
|
||||
#
|
||||
# Regeln:
|
||||
# - Verwende math.sqrt(...) für die Quadratwurzel und a**2 bzw. b**2 zum Quadrieren.
|
||||
# - Wenn a < 0 oder b < 0 ist, soll ein ValueError ausgelöst werden:
|
||||
# raise ValueError("Seitenlängen dürfen nicht negativ sein")
|
||||
# - Gib das Ergebnis mit 'return' als float zurück.
|
||||
# ==============================================================================
|
||||
|
||||
def hypotenuse(a: float, b: float) -> float:
|
||||
"""Berechnet die Hypotenuse c = sqrt(a^2 + b^2)."""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Schreibe die Funktion "zylinder_volumen(radius: float, hoehe: float) -> float".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Berechnet das Volumen eines Zylinders: V = pi * r² * h.
|
||||
#
|
||||
# Regeln:
|
||||
# - Verwende die Kreiszahl Pi aus dem math-Modul: math.pi.
|
||||
# - Wenn radius < 0 oder hoehe < 0 ist, soll ein ValueError ausgelöst werden:
|
||||
# raise ValueError("Radius und Höhe dürfen nicht negativ sein")
|
||||
# - Gib das berechnete Volumen mit 'return' zurück.
|
||||
# ==============================================================================
|
||||
|
||||
def zylinder_volumen(radius: float, hoehe: float) -> float:
|
||||
"""Berechnet das Volumen eines Zylinders: V = pi * r^2 * h."""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Schreibe die Funktion "wuerfle_wuerfel(anzahl: int, seiten: int = 6) -> list[int]".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Simuliert das Würfeln von 'anzahl' Würfeln mit jeweils 'seiten' Seiten.
|
||||
#
|
||||
# Regeln:
|
||||
# - Der Parameter 'seiten' hat den Standardwert 6 (Standard-Spielwürfel).
|
||||
# - Verwende random.randint(1, seiten), um eine Zufallszahl zwischen 1 und 'seiten'
|
||||
# (inklusive) zu erzeugen.
|
||||
# - Bei anzahl < 0 oder seiten < 1 soll ein ValueError ausgelöst werden:
|
||||
# raise ValueError("Ungültige Würfel-Parameter")
|
||||
# - Bei anzahl == 0 soll eine leere Liste [] zurückgegeben werden.
|
||||
# - Gib eine Liste mit allen gewürfelten Augenzahlen zurück.
|
||||
# ==============================================================================
|
||||
|
||||
def wuerfle_wuerfel(anzahl: int, seiten: int = 6) -> list[int]:
|
||||
"""Würfelt 'anzahl' Würfel mit je 'seiten' Seiten (Standard: 6-seitig)."""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Schreibe die Funktion "statistik(zahlen: list[float]) -> tuple[float, float, float]".
|
||||
#
|
||||
# Beschreibung:
|
||||
# Berechnet das Minimum, das Maximum und den arithmetischen Mittelwert (Durchschnitt)
|
||||
# einer Liste von Zahlen.
|
||||
#
|
||||
# Regeln:
|
||||
# - Wenn die Liste leer ist (len(zahlen) == 0), soll ein ValueError ausgelöst werden:
|
||||
# raise ValueError("Die Liste darf nicht leer sein")
|
||||
# - Berechne:
|
||||
# * min_wert = min(zahlen)
|
||||
# * max_wert = max(zahlen)
|
||||
# * mittelwert = sum(zahlen) / len(zahlen)
|
||||
# - Gib alle drei Werte als Tupel zurück:
|
||||
# return (min_wert, max_wert, mittelwert)
|
||||
# ==============================================================================
|
||||
|
||||
def statistik(zahlen: list[float]) -> tuple[float, float, float]:
|
||||
"""Gibt (min_wert, max_wert, mittelwert) einer Zahlenliste zurück."""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum manuellen Ausprobieren:
|
||||
# (Führe diese Datei aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("=" * 55)
|
||||
print("🪄 KAPITEL G06: EIGENE FUNKTIONEN & MODULE")
|
||||
print("=" * 55)
|
||||
|
||||
# 1. Pythagoras
|
||||
c = hypotenuse(3.0, 4.0)
|
||||
print(f"Hypotenuse für a=3, b=4: {c} (Erwartet: 5.0)")
|
||||
|
||||
# 2. Zylindervolumen
|
||||
v = zylinder_volumen(3.0, 5.0)
|
||||
v_str = f"{v:.2f}" if v is not None else "None"
|
||||
print(f"Zylindervolumen (r=3, h=5): {v_str} (Erwartet: ~141.37)")
|
||||
|
||||
# 3. Würfel werfen
|
||||
wuerfe_w6 = wuerfle_wuerfel(5)
|
||||
print(f"5x W6 gewürfelt: {wuerfe_w6}")
|
||||
wuerfe_w20 = wuerfle_wuerfel(3, seiten=20)
|
||||
print(f"3x W20 (D20) gewürfelt: {wuerfe_w20}")
|
||||
|
||||
# 4. Statistik mit Tuple-Unpacking
|
||||
noten = [1.0, 2.3, 1.7, 3.0, 1.3]
|
||||
stats = statistik(noten)
|
||||
if stats is not None:
|
||||
bester, schlechtester, schnitt = stats
|
||||
print(f"Notenstatistik: Beste={bester}, Schlechteste={schlechtester}, Schnitt={schnitt:.2f}")
|
||||
else:
|
||||
print(f"Notenstatistik: None (Erwartet: (1.0, 3.0, 1.86))")
|
||||
|
||||
print("=" * 55)
|
||||
print("💡 Führe 'python3 test_aufgabe.py' aus, um deine Lösungen zu prüfen!")
|
||||
285
g06_funktionen_und_module/index.html
Normal file
285
g06_funktionen_und_module/index.html
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G06: Eigene Funktionen & Module</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g05_schleifen_und_wiederholungen/index.html">← Kapitel G05</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G06</span>
|
||||
<span>›</span>
|
||||
<a href="../g07_listen_und_sequenzen/index.html">Kapitel G07 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G06 • Schulabgleich 05.0 & 05.1</div>
|
||||
<h1>Eigene Funktionen & Module 🪄📦</h1>
|
||||
<p>Lerne, wie du saubere Funktionen baust, Ergebnisse mit return zurückgibst, Variablen-Scopes verstehst und Standard-Module wie math und random nutzt.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Analogie & Grundkonzept -->
|
||||
<section class="card">
|
||||
<h2>1. Die Fabrik-Analogie: Was ist eine Funktion?</h2>
|
||||
|
||||
<p>
|
||||
Eine Funktion ist wie eine kleine, eigenständige Fabrikmaschine (oder ein Zauberkasten). Du gibst ihr Zutaten hinein, die Maschine verarbeitet sie, und am Ende liefert sie ein fertiges Produkt heraus!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏭 Das 3-Schritte-Prinzip jeder Funktion:</div>
|
||||
<ol style="margin-left: 20px; margin-top: 8px;">
|
||||
<li><strong>Input (Parameter):</strong> Die Zutaten, die du beim Aufruf übergibst (z.B. zwei Zahlen: <code>a = 3</code>, <code>b = 4</code>).</li>
|
||||
<li><strong>Verarbeitung:</strong> Die Rechenschritte im Inneren der Funktion (z.B. Satz des Pythagoras <code>c = math.sqrt(a**2 + b**2)</code>).</li>
|
||||
<li><strong>Output (<code>return</code>):</strong> Das fertige Produkt, das an dein Hauptprogramm zurückgegeben wird (z.B. <code>5.0</code>).</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. return vs print -->
|
||||
<section class="card">
|
||||
<h2>2. Der entscheidende Unterschied: <code>return</code> vs. <code>print()</code></h2>
|
||||
|
||||
<p>Das ist der häufigste Stolperstein für alle Programmieranfänger:</p>
|
||||
|
||||
<div class="extension-grid">
|
||||
<div class="extension-card" style="border-left: 4px solid var(--warning);">
|
||||
<div class="extension-icon" style="background: var(--warning-light); color: var(--warning);">🖨️</div>
|
||||
<div class="extension-info">
|
||||
<h4><code>print(...)</code></h4>
|
||||
<p>Schreibt nur Text auf den Bildschirm. Das Programm kann mit der Bildschirmausgabe <strong>nicht</strong> weiterrechnen!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="extension-card" style="border-left: 4px solid var(--success);">
|
||||
<div class="extension-icon" style="background: var(--success-light); color: var(--success);">📦</div>
|
||||
<div class="extension-info">
|
||||
<h4><code>return ...</code></h4>
|
||||
<p>Übergibt den echten Wert zurück an den Aufrufer. Du kannst das Ergebnis in Variablen speichern und weiterverwenden!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots"><span class="code-dot dot-red"></span><span class="code-dot dot-yellow"></span><span class="code-dot dot-green"></span></div>
|
||||
<span>Vergleich: print() vs. return</span>
|
||||
</div>
|
||||
<pre><span class="cm"># ❌ Falsch: Mit print() kann man nicht weiterrechnen</span>
|
||||
<span class="kw">def</span> <span class="fn">quadrat_falsch</span>(<span class="var">x</span>):
|
||||
<span class="fn">print</span>(<span class="var">x</span> * <span class="var">x</span>)
|
||||
|
||||
<span class="var">ergebnis</span> = <span class="fn">quadrat_falsch</span>(<span class="num">5</span>) <span class="cm"># Gibt 25 auf der Konsole aus, liefert aber None!</span>
|
||||
<span class="cm"># print(ergebnis + 10) # 💥 TypeError: unsupported operand type for +: 'NoneType' and 'int'</span>
|
||||
|
||||
<span class="cm"># ✅ Richtig: Mit return kann der Wert weiterverwendet werden</span>
|
||||
<span class="kw">def</span> <span class="fn">quadrat_richtig</span>(<span class="var">x</span>):
|
||||
<span class="kw">return</span> <span class="var">x</span> * <span class="var">x</span>
|
||||
|
||||
<span class="var">ergebnis</span> = <span class="fn">quadrat_richtig</span>(<span class="num">5</span>) <span class="cm"># ergebnis ist jetzt der echte Wert 25!</span>
|
||||
<span class="fn">print</span>(<span class="var">ergebnis</span> + <span class="num">10</span>) <span class="cm"># Funktioniert perfekt -> Ausgabe: 35</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Parameter, Default-Werte & Tupel-Return -->
|
||||
<section class="card">
|
||||
<h2>3. Standardwerte (Defaults) & Mehrere Rückgabewerte</h2>
|
||||
|
||||
<p>Du kannst Parametern Standardwerte geben, die verwendet werden, wenn beim Aufruf kein Wert übergeben wird:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots"><span class="code-dot dot-red"></span><span class="code-dot dot-yellow"></span><span class="code-dot dot-green"></span></div>
|
||||
<span>Python (Standardwerte und Tupel-Return)</span>
|
||||
</div>
|
||||
<pre><span class="cm"># Standardwert seiten=6 (W6 Spielwürfel)</span>
|
||||
<span class="kw">def</span> <span class="fn">wuerfeln</span>(<span class="var">anzahl</span>: <span class="fn">int</span>, <span class="var">seiten</span>: <span class="fn">int</span> = <span class="num">6</span>) -> <span class="fn">list</span>[<span class="fn">int</span>]:
|
||||
<span class="var">ergebnisse</span> = []
|
||||
<span class="kw">for</span> <span class="var">_</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="var">anzahl</span>):
|
||||
<span class="var">ergebnisse</span>.<span class="fn">append</span>(<span class="var">random</span>.<span class="fn">randint</span>(<span class="num">1</span>, <span class="var">seiten</span>))
|
||||
<span class="kw">return</span> <span class="var">ergebnisse</span>
|
||||
|
||||
<span class="fn">print</span>(<span class="fn">wuerfeln</span>(<span class="num">3</span>)) <span class="cm"># 3 normale 6-seitige Würfel</span>
|
||||
<span class="fn">print</span>(<span class="fn">wuerfeln</span>(<span class="num">2</span>, <span class="var">seiten</span>=<span class="num">20</span>)) <span class="cm"># 2 20-seitige D20-Würfel</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>Mehrere Werte zurückgeben (Tuple-Unpacking):</h3>
|
||||
<p>Trenne Rückgabewerte einfach mit Kommas. Beim Aufruf kannst du sie direkt in separate Variablen entpacken:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Python (Mehrere Rückgabewerte)</span>
|
||||
</div>
|
||||
<pre><span class="kw">def</span> <span class="fn">min_max_spanne</span>(<span class="var">werte</span>: <span class="fn">list</span>[<span class="fn">float</span>]) -> <span class="fn">tuple</span>[<span class="fn">float</span>, <span class="fn">float</span>]:
|
||||
<span class="kw">return</span> <span class="fn">min</span>(<span class="var">werte</span>), <span class="fn">max</span>(<span class="var">werte</span>)
|
||||
|
||||
<span class="cm"># Beide Werte auf einmal entpacken:</span>
|
||||
<span class="var">tiefster</span>, <span class="var">hoechster</span> = <span class="fn">min_max_spanne</span>([<span class="num">12.5</span>, <span class="num">3.1</span>, <span class="num">18.9</span>])
|
||||
<span class="fn">print</span>(<span class="str">f"Minimum: {tiefster}, Maximum: {hoechster}"</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Scope: Lokal vs. Global -->
|
||||
<section class="card">
|
||||
<h2>4. Gültigkeitsbereich: Lokaler vs. Globaler Scope 🏠</h2>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">🏨 Die Hotelzimmer-Regel:</div>
|
||||
Variablen, die <strong>innerhalb</strong> einer Funktion erstellt werden (z.B. Zwischenergebnisse oder Zähler), sind <strong>lokal</strong>. Sie existieren nur für die Dauer des Funktionsaufrufs und sind von außen unsichtbar und unzugänglich.
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Scope-Veranschaulichung</span></div>
|
||||
<pre><span class="var">globaler_name</span> = <span class="str">"Alice"</span> <span class="cm"># Überall im gesamten Programm sichtbar</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">geheimnis</span>():
|
||||
<span class="var">lokales_passwort</span> = <span class="str">"Geheim123"</span> <span class="cm"># Nur HIER DRINNEN sichtbar!</span>
|
||||
<span class="fn">print</span>(<span class="str">"In Funktion:"</span>, <span class="var">lokales_passwort</span>)
|
||||
|
||||
<span class="fn">geheimnis</span>()
|
||||
<span class="cm"># print(lokales_passwort) # 💥 NameError: name 'lokales_passwort' is not defined!</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Die Standardbibliothek Module -->
|
||||
<section class="card">
|
||||
<h2>5. Die Python-Werkzeugkiste: Module <code>math</code> & <code>random</code></h2>
|
||||
|
||||
<p>Python bringt hunderte nützliche Module mit. Du bindest sie mit <code>import modulname</code> am Anfang deiner Datei ein:</p>
|
||||
|
||||
<div class="extension-grid">
|
||||
<div class="extension-card">
|
||||
<div class="extension-icon" style="background: #e0f2fe; color: #0284c7;">📐</div>
|
||||
<div class="extension-info">
|
||||
<h4>Modul <code>math</code></h4>
|
||||
<p><strong><code>math.sqrt(x)</code>:</strong> Quadratwurzel von x<br>
|
||||
<strong><code>math.pi</code>:</strong> Kreiszahl π ≈ 3.14159...<br>
|
||||
<strong><code>math.pow(b, e)</code>:</strong> Potenzieren $b^e$<br>
|
||||
<strong><code>math.floor(x)</code> / <code>math.ceil(x)</code>:</strong> Ab-/Aufrunden</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="extension-card">
|
||||
<div class="extension-icon" style="background: #fdf4ff; color: #a855f7;">🎲</div>
|
||||
<div class="extension-info">
|
||||
<h4>Modul <code>random</code></h4>
|
||||
<p><strong><code>random.randint(a, b)</code>:</strong> Zufalls-Ganzzahl von a bis b<br>
|
||||
<strong><code>random.random()</code>:</strong> Zufalls-Float zwischen 0.0 und 1.0<br>
|
||||
<strong><code>random.choice(liste)</code>:</strong> Zufälliges Element wählen<br>
|
||||
<strong><code>random.shuffle(liste)</code>:</strong> Liste mischen</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. Aufgaben & Checkliste -->
|
||||
<section class="card">
|
||||
<h2>6. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g06_funktionen_und_module/aufgabe.py</code> und bearbeite die folgenden 4 Aufgaben:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1: <code>hypotenuse(a: float, b: float) -> float</code></strong><br>
|
||||
Berechnet $c = \sqrt{a^2 + b^2}$ mittels <code>math.sqrt</code>. Löst einen <code>ValueError</code> aus bei negativen Seitenlängen.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2: <code>zylinder_volumen(radius: float, hoehe: float) -> float</code></strong><br>
|
||||
Berechnet $V = \pi \cdot r^2 \cdot h$ mittels <code>math.pi</code>. Löst einen <code>ValueError</code> aus, wenn <code>radius < 0</code> oder <code>hoehe < 0</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3: <code>wuerfle_wuerfel(anzahl: int, seiten: int = 6) -> list[int]</code></strong><br>
|
||||
Simuliert Würfe mit <code>random.randint(1, seiten)</code>. Standardwert ist <code>seiten=6</code>. Löst einen <code>ValueError</code> aus bei <code>anzahl < 0</code> oder <code>seiten < 1</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4: <code>statistik(zahlen: list[float]) -> tuple[float, float, float]</code></strong><br>
|
||||
Gibt das 3er-Tupel <code>(min_wert, max_wert, mittelwert)</code> zurück. Löst einen <code>ValueError</code> aus, falls die Liste leer ist.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 1 & 2 (Geometrie mit math)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">import</span> <span class="var">math</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">hypotenuse</span>(<span class="var">a</span>: <span class="fn">float</span>, <span class="var">b</span>: <span class="fn">float</span>) -> <span class="fn">float</span>:
|
||||
<span class="kw">if</span> <span class="var">a</span> < <span class="num">0</span> <span class="kw">or</span> <span class="var">b</span> < <span class="num">0</span>:
|
||||
<span class="kw">raise</span> <span class="fn">ValueError</span>(<span class="str">"Seitenlängen dürfen nicht negativ sein"</span>)
|
||||
<span class="kw">return</span> <span class="var">math</span>.<span class="fn">sqrt</span>(<span class="var">a</span>**<span class="num">2</span> + <span class="var">b</span>**<span class="num">2</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Würfelsimulator mit random)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">import</span> <span class="var">random</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">wuerfle_wuerfel</span>(<span class="var">anzahl</span>: <span class="fn">int</span>, <span class="var">seiten</span>: <span class="fn">int</span> = <span class="num">6</span>) -> <span class="fn">list</span>[<span class="fn">int</span>]:
|
||||
<span class="kw">if</span> <span class="var">anzahl</span> < <span class="num">0</span> <span class="kw">or</span> <span class="var">seiten</span> < <span class="num">1</span>:
|
||||
<span class="kw">raise</span> <span class="fn">ValueError</span>(<span class="str">"Ungültige Würfel-Parameter"</span>)
|
||||
<span class="var">ergebnisse</span> = []
|
||||
<span class="kw">for</span> <span class="var">_</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="var">anzahl</span>):
|
||||
<span class="var">ergebnisse</span>.<span class="fn">append</span>(<span class="var">random</span>.<span class="fn">randint</span>(<span class="num">1</span>, <span class="var">seiten</span>))
|
||||
<span class="kw">return</span> <span class="var">ergebnisse</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 4 (Statistik & Tupel-Return)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">statistik</span>(<span class="var">zahlen</span>: <span class="fn">list</span>[<span class="fn">float</span>]) -> <span class="fn">tuple</span>[<span class="fn">float</span>, <span class="fn">float</span>, <span class="fn">float</span>]:
|
||||
<span class="kw">if</span> <span class="kw">not</span> <span class="var">zahlen</span>:
|
||||
<span class="kw">raise</span> <span class="fn">ValueError</span>(<span class="str">"Die Liste darf nicht leer sein"</span>)
|
||||
<span class="kw">return</span> <span class="fn">min</span>(<span class="var">zahlen</span>), <span class="fn">max</span>(<span class="var">zahlen</span>), <span class="fn">sum</span>(<span class="var">zahlen</span>) / <span class="fn">len</span>(<span class="var">zahlen</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 7. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>7. 🧪 Testen & Weitergehen</h2>
|
||||
<p>Führe im Terminal den Unittest aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g05_schleifen_und_wiederholungen/index.html" class="btn btn-secondary">← Zurück zu Kapitel G05</a>
|
||||
<a href="../g07_listen_und_sequenzen/index.html" class="btn">Weiter zu Kapitel G07 (Listen & Sequenzen) →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
51
g06_funktionen_und_module/musterloesung.py
Normal file
51
g06_funktionen_und_module/musterloesung.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
"""
|
||||
Kapitel G06: Eigene Funktionen & Module – Musterlösung
|
||||
=====================================================
|
||||
Schulabgleich: 05.0 & 05.1
|
||||
"""
|
||||
|
||||
import math
|
||||
import random
|
||||
|
||||
|
||||
def hypotenuse(a: float, b: float) -> float:
|
||||
"""Berechnet die Hypotenuse c = sqrt(a^2 + b^2)."""
|
||||
if a < 0 or b < 0:
|
||||
raise ValueError("Seitenlängen dürfen nicht negativ sein")
|
||||
return math.sqrt(a**2 + b**2)
|
||||
|
||||
|
||||
def zylinder_volumen(radius: float, hoehe: float) -> float:
|
||||
"""Berechnet das Volumen eines Zylinders: V = pi * r^2 * h."""
|
||||
if radius < 0 or hoehe < 0:
|
||||
raise ValueError("Radius und Höhe dürfen nicht negativ sein")
|
||||
return math.pi * (radius**2) * hoehe
|
||||
|
||||
|
||||
def wuerfle_wuerfel(anzahl: int, seiten: int = 6) -> list[int]:
|
||||
"""Würfelt 'anzahl' Würfel mit je 'seiten' Seiten (Standard: 6-seitig)."""
|
||||
if anzahl < 0 or seiten < 1:
|
||||
raise ValueError("Ungültige Würfel-Parameter")
|
||||
ergebnisse = []
|
||||
for _ in range(anzahl):
|
||||
augen = random.randint(1, seiten)
|
||||
ergebnisse.append(augen)
|
||||
return ergebnisse
|
||||
|
||||
|
||||
def statistik(zahlen: list[float]) -> tuple[float, float, float]:
|
||||
"""Gibt (min_wert, max_wert, mittelwert) einer Zahlenliste zurück."""
|
||||
if not zahlen:
|
||||
raise ValueError("Die Liste darf nicht leer sein")
|
||||
min_wert = min(zahlen)
|
||||
max_wert = max(zahlen)
|
||||
mittelwert = sum(zahlen) / len(zahlen)
|
||||
return min_wert, max_wert, mittelwert
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Musterlösung G06 Demonstrationen:")
|
||||
print("hypotenuse(3, 4) =", hypotenuse(3.0, 4.0))
|
||||
print("zylinder_volumen(3, 5) =", zylinder_volumen(3.0, 5.0))
|
||||
print("wuerfle_wuerfel(5) =", wuerfle_wuerfel(5))
|
||||
print("statistik([10, 20, 30]) =", statistik([10.0, 20.0, 30.0]))
|
||||
167
g06_funktionen_und_module/test_aufgabe.py
Normal file
167
g06_funktionen_und_module/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
"""
|
||||
Testsuite für Kapitel G06: Eigene Funktionen & Module
|
||||
=====================================================
|
||||
Schulabgleich: 05.0 & 05.1
|
||||
"""
|
||||
|
||||
import math
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das aktuelle Verzeichnis im Modulpfad ist
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG06(unittest.TestCase):
|
||||
|
||||
def test_01_hypotenuse(self):
|
||||
"""Prüft die Funktion hypotenuse(a, b)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "hypotenuse"),
|
||||
"Fehler: Die Funktion 'hypotenuse' fehlt in aufgabe.py!"
|
||||
)
|
||||
res = aufgabe.hypotenuse(3.0, 4.0)
|
||||
self.assertIsNotNone(
|
||||
res,
|
||||
"Fehler: hypotenuse(3.0, 4.0) gibt None zurück. Vergiss nicht das 'return'!"
|
||||
)
|
||||
# Standard rechtwinklige Dreiecke
|
||||
self.assertAlmostEqual(
|
||||
res, 5.0, places=4,
|
||||
msg="Fehler: hypotenuse(3.0, 4.0) sollte 5.0 sein (3-4-5 Dreieck)!"
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
aufgabe.hypotenuse(5.0, 12.0), 13.0, places=4,
|
||||
msg="Fehler: hypotenuse(5.0, 12.0) sollte 13.0 sein (5-12-13 Dreieck)!"
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
aufgabe.hypotenuse(6.0, 8.0), 10.0, places=4,
|
||||
msg="Fehler: hypotenuse(6.0, 8.0) sollte 10.0 sein!"
|
||||
)
|
||||
# Fehlerbehandlung für negative Längen
|
||||
with self.assertRaises(ValueError, msg="Fehler: hypotenuse(-3.0, 4.0) muss einen ValueError auslösen!"):
|
||||
aufgabe.hypotenuse(-3.0, 4.0)
|
||||
with self.assertRaises(ValueError, msg="Fehler: hypotenuse(3.0, -4.0) muss einen ValueError auslösen!"):
|
||||
aufgabe.hypotenuse(3.0, -4.0)
|
||||
|
||||
def test_02_zylinder_volumen(self):
|
||||
"""Prüft die Funktion zylinder_volumen(radius, hoehe)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "zylinder_volumen"),
|
||||
"Fehler: Die Funktion 'zylinder_volumen' fehlt in aufgabe.py!"
|
||||
)
|
||||
res = aufgabe.zylinder_volumen(3.0, 5.0)
|
||||
self.assertIsNotNone(
|
||||
res,
|
||||
"Fehler: zylinder_volumen(3.0, 5.0) gibt None zurück. Vergiss nicht das 'return'!"
|
||||
)
|
||||
# V = pi * r^2 * h
|
||||
# Für r=3, h=5 -> pi * 9 * 5 = 45 * pi ≈ 141.3716694
|
||||
erwartet = math.pi * 9 * 5
|
||||
self.assertAlmostEqual(
|
||||
res, erwartet, places=4,
|
||||
msg=f"Fehler: zylinder_volumen(3.0, 5.0) sollte {erwartet:.4f} sein!"
|
||||
)
|
||||
# Für r=1, h=1 -> pi
|
||||
self.assertAlmostEqual(
|
||||
aufgabe.zylinder_volumen(1.0, 1.0), math.pi, places=4,
|
||||
msg="Fehler: zylinder_volumen(1.0, 1.0) sollte math.pi entsprechen!"
|
||||
)
|
||||
# Für r=0, h=10 -> 0.0
|
||||
self.assertAlmostEqual(
|
||||
aufgabe.zylinder_volumen(0.0, 10.0), 0.0, places=4,
|
||||
msg="Fehler: zylinder_volumen(0.0, 10.0) sollte 0.0 sein!"
|
||||
)
|
||||
# Fehlerbehandlung für negative Werte
|
||||
with self.assertRaises(ValueError, msg="Fehler: zylinder_volumen(-1.0, 5.0) muss einen ValueError auslösen!"):
|
||||
aufgabe.zylinder_volumen(-1.0, 5.0)
|
||||
with self.assertRaises(ValueError, msg="Fehler: zylinder_volumen(2.0, -3.0) muss einen ValueError auslösen!"):
|
||||
aufgabe.zylinder_volumen(2.0, -3.0)
|
||||
|
||||
def test_03_wuerfle_wuerfel_standard(self):
|
||||
"""Prüft wuerfle_wuerfel mit Standardwert seiten=6."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "wuerfle_wuerfel"),
|
||||
"Fehler: Die Funktion 'wuerfle_wuerfel' fehlt in aufgabe.py!"
|
||||
)
|
||||
wuerfe = aufgabe.wuerfle_wuerfel(20)
|
||||
self.assertIsInstance(
|
||||
wuerfe, list,
|
||||
"Fehler: wuerfle_wuerfel muss eine Liste zurückgeben!"
|
||||
)
|
||||
self.assertEqual(len(wuerfe), 20, "Fehler: Bei anzahl=20 müssen 20 Würfelergebnisse geliefert werden!")
|
||||
for w in wuerfe:
|
||||
self.assertIsInstance(w, int, "Fehler: Jedes Würfelergebnis muss eine ganze Zahl (int) sein!")
|
||||
self.assertTrue(1 <= w <= 6, f"Fehler: Würfelergebnis {w} liegt nicht zwischen 1 und 6!")
|
||||
|
||||
# 0 Würfel
|
||||
leer = aufgabe.wuerfle_wuerfel(0)
|
||||
self.assertEqual(leer, [], "Fehler: wuerfle_wuerfel(0) sollte eine leere Liste [] zurückgeben!")
|
||||
|
||||
def test_04_wuerfle_wuerfel_custom_seiten(self):
|
||||
"""Prüft wuerfle_wuerfel mit benutzerdefinierter Seitenzahl (z.B. W20)."""
|
||||
wuerfe_w20 = aufgabe.wuerfle_wuerfel(25, seiten=20)
|
||||
self.assertIsInstance(
|
||||
wuerfe_w20, list,
|
||||
"Fehler: wuerfle_wuerfel(25, seiten=20) muss eine Liste zurückgeben!"
|
||||
)
|
||||
self.assertEqual(len(wuerfe_w20), 25)
|
||||
for w in wuerfe_w20:
|
||||
self.assertTrue(1 <= w <= 20, f"Fehler: W20-Ergebnis {w} liegt nicht im Bereich [1, 20]!")
|
||||
|
||||
# W2 (Münzwurf)
|
||||
wuerfe_w2 = aufgabe.wuerfle_wuerfel(10, seiten=2)
|
||||
self.assertIsInstance(wuerfe_w2, list)
|
||||
for w in wuerfe_w2:
|
||||
self.assertIn(w, [1, 2], f"Fehler: W2-Ergebnis {w} darf nur 1 oder 2 sein!")
|
||||
|
||||
def test_05_wuerfle_wuerfel_ungueltig(self):
|
||||
"""Prüft ungültige Argumente bei wuerfle_wuerfel."""
|
||||
with self.assertRaises(ValueError, msg="Fehler: wuerfle_wuerfel(-1) muss ValueError auslösen!"):
|
||||
aufgabe.wuerfle_wuerfel(-1)
|
||||
with self.assertRaises(ValueError, msg="Fehler: wuerfle_wuerfel(5, seiten=0) muss ValueError auslösen!"):
|
||||
aufgabe.wuerfle_wuerfel(5, seiten=0)
|
||||
with self.assertRaises(ValueError, msg="Fehler: wuerfle_wuerfel(5, seiten=-4) muss ValueError auslösen!"):
|
||||
aufgabe.wuerfle_wuerfel(5, seiten=-4)
|
||||
|
||||
def test_06_statistik(self):
|
||||
"""Prüft die Funktion statistik(zahlen)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "statistik"),
|
||||
"Fehler: Die Funktion 'statistik' fehlt in aufgabe.py!"
|
||||
)
|
||||
zahlen = [10.0, 20.0, 30.0, 40.0, 50.0]
|
||||
ergebnis = aufgabe.statistik(zahlen)
|
||||
self.assertIsInstance(
|
||||
ergebnis, tuple,
|
||||
"Fehler: statistik(...) muss ein Tupel (min_wert, max_wert, mittelwert) zurückgeben!"
|
||||
)
|
||||
self.assertEqual(len(ergebnis), 3, "Fehler: Das Ergebnis-Tupel muss genau 3 Elemente haben!")
|
||||
|
||||
min_w, max_w, mittel = ergebnis
|
||||
self.assertEqual(min_w, 10.0, "Fehler: Minimum von [10, 20, 30, 40, 50] sollte 10.0 sein!")
|
||||
self.assertEqual(max_w, 50.0, "Fehler: Maximum von [10, 20, 30, 40, 50] sollte 50.0 sein!")
|
||||
self.assertEqual(mittel, 30.0, "Fehler: Mittelwert von [10, 20, 30, 40, 50] sollte 30.0 sein!")
|
||||
|
||||
# Einzelelement
|
||||
einz = aufgabe.statistik([7.5])
|
||||
self.assertIsInstance(einz, tuple)
|
||||
einz_min, einz_max, einz_mit = einz
|
||||
self.assertEqual(einz_min, 7.5)
|
||||
self.assertEqual(einz_max, 7.5)
|
||||
self.assertEqual(einz_mit, 7.5)
|
||||
|
||||
def test_07_statistik_leere_liste(self):
|
||||
"""Prüft Fehlerbehandlung bei leerer Liste in statistik()."""
|
||||
with self.assertRaises(ValueError, msg="Fehler: statistik([]) für eine leere Liste muss einen ValueError auslösen!"):
|
||||
aufgabe.statistik([])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
136
g07_listen_und_sequenzen/README.md
Normal file
136
g07_listen_und_sequenzen/README.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Kapitel G07: Listen & Sequenzen in Python 🚂📋
|
||||
|
||||
Willkommen im Kapitel **Listen und Sequenzen**! Listen gehören zu den wichtigsten und am häufigsten verwendeten Datenstrukturen in Python. Mit ihnen kannst du mehrere Daten geordnet in einer einzigen Variable speichern.
|
||||
|
||||
---
|
||||
|
||||
## 🚂 1. Die Zugwaggon-Analogie: Was ist eine Liste?
|
||||
|
||||
Stell dir eine Liste wie einen **Zug mit durchnummerierten Waggons** vor:
|
||||
|
||||
```text
|
||||
┌───────────┬───────────┬───────────┬───────────┬───────────┐
|
||||
Werte: │ "Apfel" │ "Banane" │ "Kirsche"│ "Dattel" │ "Erdbeere"
|
||||
└───────────┴───────────┴───────────┴───────────┴───────────┘
|
||||
Positiver Index: 0 1 2 3 4
|
||||
Negativer Index: -5 -4 -3 -2 -1
|
||||
```
|
||||
|
||||
- **Eckige Klammern `[]`:** Definieren eine Liste (`fruechte = ["Apfel", "Banane", "Kirsche"]`).
|
||||
- **Indexierung ab 0:** Der erste Waggon ist immer Index `0`!
|
||||
- **Negativer Index:** `-1` ist immer das letzte Element, `-2` das vorletzte.
|
||||
- **Veränderbarkeit (mutable):** Du kannst Waggons austauschen, neue anhängen oder abkoppeln!
|
||||
|
||||
---
|
||||
|
||||
## ✂️ 2. Slicing: Teile einer Liste herausschneiden
|
||||
|
||||
Mit dem **Slice-Operator `[start:stop:step]`** kannst du beliebige Abschnitte aus einer Sequenz herausschneiden:
|
||||
|
||||
```python
|
||||
zahlen = [10, 20, 30, 40, 50, 60]
|
||||
|
||||
# 1. Bereich von Index 1 bis vor Index 4:
|
||||
print(zahlen[1:4]) # -> [20, 30, 40]
|
||||
|
||||
# 2. Vom Anfang bis vor Index 3:
|
||||
print(zahlen[:3]) # -> [10, 20, 30]
|
||||
|
||||
# 3. Ab Index 3 bis zum Ende:
|
||||
print(zahlen[3:]) # -> [40, 50, 60]
|
||||
|
||||
# 4. Jedes 2. Element (Schrittweite 2):
|
||||
print(zahlen[::2]) # -> [10, 30, 50]
|
||||
|
||||
# 5. Ganze Liste umkehren (Rückwärts-Schritt):
|
||||
print(zahlen[::-1]) # -> [60, 50, 40, 30, 20, 10]
|
||||
```
|
||||
|
||||
> 💡 **Merke:** Der `stop`-Index ist immer **exklusiv** (wird nicht mehr mitgenommen). `zahlen[1:4]` nimmt also die Indizes 1, 2 und 3.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 3. Die wichtigsten Listen-Methoden
|
||||
|
||||
Listen bringen viele eingebaute Methoden mit, um Elemente hinzuzufügen, zu löschen oder zu sortieren:
|
||||
|
||||
| Methode | Beschreibung | Beispiel |
|
||||
| :--- | :--- | :--- |
|
||||
| `.append(x)` | Fügt `x` ans Ende der Liste an | `tiere.append("Hund")` |
|
||||
| `.insert(i, x)` | Fügt `x` an Position `i` ein | `tiere.insert(0, "Katze")` |
|
||||
| `.remove(x)` | Entfernt das erste Vorkommen von `x` | `tiere.remove("Hund")` *(wirft Fehler, wenn `x` fehlt!)* |
|
||||
| `.pop()` | Entfernt und liefert das letzte Element | `letztes = tiere.pop()` |
|
||||
| `.pop(i)` | Entfernt und liefert Element an Index `i` | `erstes = tiere.pop(0)` |
|
||||
| `.sort()` | Sortiert die Liste aufsteigend in-place | `zahlen.sort()` |
|
||||
| `.reverse()` | Dreht die Liste an Ort und Stelle um | `zahlen.reverse()` |
|
||||
|
||||
---
|
||||
|
||||
## 🧮 4. Nützliche eingebaute Funktionen & `in`-Operator
|
||||
|
||||
Python bietet praktische globale Funktionen für Sequenzen:
|
||||
|
||||
```python
|
||||
noten = [1.5, 2.0, 3.7, 1.0, 2.3]
|
||||
|
||||
# Länge (Anzahl der Elemente):
|
||||
print(len(noten)) # -> 5
|
||||
|
||||
# Kleinster und größter Wert:
|
||||
print(min(noten)) # -> 1.0 (beste Note)
|
||||
print(max(noten)) # -> 3.7 (schlechteste Note)
|
||||
|
||||
# Summe aller Zahlen:
|
||||
print(sum(noten)) # -> 10.5
|
||||
|
||||
# Notendurchschnitt:
|
||||
schnitt = sum(noten) / len(noten)
|
||||
print(f"Durchschnitt: {schnitt:.2f}") # -> 2.10
|
||||
|
||||
# Prüfen, ob ein Element enthalten ist:
|
||||
if 1.0 in noten:
|
||||
print("Glückwunsch zur Bestnote!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛒 5. Praxisbeispiel: Einkaufsliste verwalten
|
||||
|
||||
```python
|
||||
# ==============================================================================
|
||||
# Einkaufslisten-Manager
|
||||
# ==============================================================================
|
||||
einkauf = ["Milch", "Brot", "Käse"]
|
||||
|
||||
# 1. Etwas hinzufügen:
|
||||
einkauf.append("Äpfel")
|
||||
|
||||
# 2. Prüfen und sicher entfernen:
|
||||
artikel = "Brot"
|
||||
if artikel in einkauf:
|
||||
einkauf.remove(artikel)
|
||||
print(f"✅ '{artikel}' wurde eingekauft und abgehakt.")
|
||||
else:
|
||||
print(f"❌ '{artikel}' stand nicht auf der Liste.")
|
||||
|
||||
# 3. Sortiert ausgeben:
|
||||
einkauf.sort()
|
||||
print("Verbleibende Einkäufe:", einkauf)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `aufgabe.py` und implementiere die 5 Funktionen:
|
||||
|
||||
1. **`liste_umdrehen(liste)`**: Gibt eine neue, umgedrehte Liste zurück, ohne das Original zu verändern.
|
||||
2. **`filtere_positive_zahlen(zahlen)`**: Filtert nur Zahlen `> 0` heraus.
|
||||
3. **`entferne_element(liste, element)`**: Entfernt das Element sicher (ohne `ValueError` Absturz) und gibt `True` zurück, wenn es gefunden wurde, sonst `False`.
|
||||
4. **`mittlere_elemente(liste)`**: Schneidet mit Slicing das erste und letzte Element ab. Bei `<= 2` Elementen wird `[]` zurückgegeben.
|
||||
5. **`noten_durchschnitt_ohne_ausreisser(noten)`**: Entfernt Minimum und Maximum aus einer Kopie der Liste und berechnet den bereinigten Schnitt.
|
||||
|
||||
### Testen deiner Lösung:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
131
g07_listen_und_sequenzen/aufgabe.py
Normal file
131
g07_listen_und_sequenzen/aufgabe.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
"""
|
||||
Kapitel G07: Listen & Sequenzen in Python (Schulabgleich 09.0 & 11.0)
|
||||
====================================================================
|
||||
|
||||
In dieser Aufgabe vertiefst du dein Wissen über Python-Listen, Indexierung,
|
||||
Slicing, Listen-Methoden und nützliche eingebaute Funktionen.
|
||||
"""
|
||||
|
||||
|
||||
def liste_umdrehen(liste: list) -> list:
|
||||
"""
|
||||
TODO 1: Gibt eine NEUE Liste zurück, deren Elemente in umgekehrter
|
||||
Reihenfolge angeordnet sind. Die Original-Liste darf nicht verändert werden!
|
||||
|
||||
Beispiel:
|
||||
liste_umdrehen([1, 2, 3, 4]) -> [4, 3, 2, 1]
|
||||
liste_umdrehen(["A", "B", "C"]) -> ["C", "B", "A"]
|
||||
|
||||
Tipp:
|
||||
Verwende Slicing mit Schrittweite -1: `liste[::-1]`
|
||||
oder erstelle eine Kopie und wende `.reverse()` an.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
def filtere_positive_zahlen(zahlen: list[float]) -> list[float]:
|
||||
"""
|
||||
TODO 2: Gibt eine neue Liste zurück, die nur die echten positiven Zahlen
|
||||
(Zahl > 0) aus der übergebenen Liste enthält. 0 und negative Zahlen werden ignoriert.
|
||||
|
||||
Beispiel:
|
||||
filtere_positive_zahlen([-3, 5, 0, 12, -1, 8.5]) -> [5, 12, 8.5]
|
||||
|
||||
Tipp:
|
||||
Erstelle eine leere Ergebnisliste `positiv = []` und iteriere mit einer
|
||||
for-Schleife über alle Zahlen. Wenn `z > 0`, füge sie mit `.append(z)` hinzu.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
def entferne_element(liste: list, element) -> bool:
|
||||
"""
|
||||
TODO 3: Entfernt das erste Vorkommen von 'element' aus der übergebenen 'liste'.
|
||||
- Wenn das Element in der Liste vorkommt: Entferne es und gib True zurück.
|
||||
- Wenn das Element NICHT in der Liste ist: Ändere die Liste nicht und gib False zurück.
|
||||
|
||||
WICHTIG: Die Funktion darf keinen Fehler (ValueError) werfen!
|
||||
|
||||
Beispiel:
|
||||
namen = ["Anna", "Ben", "Clara"]
|
||||
entferne_element(namen, "Ben") -> True (namen ist jetzt ["Anna", "Clara"])
|
||||
entferne_element(namen, "David") -> False (namen bleibt ["Anna", "Clara"])
|
||||
|
||||
Tipp:
|
||||
Prüfe zuerst mit `if element in liste:`, bevor du `liste.remove(element)` aufrufst.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
def mittlere_elemente(liste: list) -> list:
|
||||
"""
|
||||
TODO 4: Gibt einen Teil der Liste zurück, der weder das erste (Index 0)
|
||||
noch das letzte (Index -1) Element enthält.
|
||||
- Wenn die Liste 2 oder weniger Elemente hat, gib eine leere Liste [] zurück.
|
||||
|
||||
Beispiel:
|
||||
mittlere_elemente([10, 20, 30, 40, 50]) -> [20, 30, 40]
|
||||
mittlere_elemente(["Start", "Mitte", "Ende"]) -> ["Mitte"]
|
||||
mittlere_elemente([1, 2]) -> []
|
||||
mittlere_elemente([]) -> []
|
||||
|
||||
Tipp:
|
||||
Nutze Slicing: `liste[1:-1]`. Wenn `len(liste) <= 2`, gib `[]` zurück.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
def noten_durchschnitt_ohne_ausreisser(noten: list[float]) -> float:
|
||||
"""
|
||||
TODO 5: Berechnet den Notendurchschnitt, nachdem die beste (niedrigste Zahl)
|
||||
und die schlechteste Note (höchste Zahl) entfernt wurden.
|
||||
- Bei weniger als 3 Noten kann kein sinnvoller bereinigter Schnitt berechnet werden;
|
||||
gib in diesem Fall 0.0 zurück.
|
||||
- Die übergebene Liste 'noten' darf nicht dauerhaft verändert werden!
|
||||
|
||||
Beispiel:
|
||||
noten_durchschnitt_ohne_ausreisser([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||
-> Beste Note: 1.0, Schlechteste Note: 5.0 werden entfernt.
|
||||
-> Verbleibende Noten: [2.0, 3.0, 4.0]
|
||||
-> Durchschnitt: (2.0 + 3.0 + 4.0) / 3 = 3.0
|
||||
|
||||
Tipp:
|
||||
1. Wenn `len(noten) < 3`: `return 0.0`
|
||||
2. Erstelle eine Kopie der Liste: `kopie = list(noten)`
|
||||
3. Finde Minimum mit `min(kopie)` und Maximum mit `max(kopie)`.
|
||||
4. Entferne je ein Exemplar mit `kopie.remove(...)`.
|
||||
5. Berechne den Schnitt mit `sum(kopie) / len(kopie)` und gib ihn zurück.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 5:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Führe die Datei aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("--- Teste deine Listen-Funktionen ---")
|
||||
|
||||
test_liste = [10, 20, 30, 40, 50]
|
||||
print("Original:", test_liste)
|
||||
print("Umgedreht (TODO 1):", liste_umdrehen(test_liste))
|
||||
|
||||
zahlen = [-5, 12, 0, -3, 42, 7]
|
||||
print("Positive Zahlen (TODO 2):", filtere_positive_zahlen(zahlen))
|
||||
|
||||
tiere = ["Hund", "Katze", "Maus"]
|
||||
erfolg = entferne_element(tiere, "Katze")
|
||||
print(f"Katze entfernt (TODO 3)? {erfolg} -> Rest: {tiere}")
|
||||
erfolg_fehlt = entferne_element(tiere, "Elefant")
|
||||
print(f"Elefant entfernt (TODO 3)? {erfolg_fehlt} -> Rest: {tiere}")
|
||||
|
||||
print("Mittlere Elemente von [1, 2, 3, 4, 5] (TODO 4):", mittlere_elemente([1, 2, 3, 4, 5]))
|
||||
|
||||
noten = [1.0, 2.0, 3.0, 4.0, 5.0]
|
||||
schnitt = noten_durchschnitt_ohne_ausreisser(noten)
|
||||
print(f"Bereinigter Notenschnitt von {noten} (TODO 5): {schnitt}")
|
||||
276
g07_listen_und_sequenzen/index.html
Normal file
276
g07_listen_und_sequenzen/index.html
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G07: Listen & Sequenzen in Python</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g06_funktionen_und_module/index.html">Kapitel G06</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G07</span>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G07 (Schulabgleich 09.0 & 11.0)</div>
|
||||
<h1>Listen & Sequenzen in Python 🚂📋</h1>
|
||||
<p>Lerne, wie du Daten in Listen sammelst, mit Index und Slicing zuschneidest und mit Methoden verwaltest.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Zugwaggon-Analogie & Indexierung -->
|
||||
<section class="card">
|
||||
<h2>1. 🚂 Die Zugwaggon-Analogie: Was ist eine Liste?</h2>
|
||||
|
||||
<p>
|
||||
Eine <strong>Liste (<code>list</code>)</strong> ist ein geordneter Behälter für mehrere Werte.
|
||||
Du kannst dir eine Liste wie einen <strong>Zug mit durchnummerierten Waggons</strong> vorstellen:
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">Zugwaggons & Indexe:</div>
|
||||
<p>Jedes Element hat einen festen Platzhalter – den <strong>Index</strong>. Python zählt immer ab <strong>0</strong>!</p>
|
||||
|
||||
<div style="overflow-x: auto; margin-top: 15px;">
|
||||
<table style="width: 100%; border-collapse: collapse; text-align: center; font-family: var(--font-mono); font-size: 0.95rem;">
|
||||
<tr style="background: var(--primary); color: white;">
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">Positiver Index</th>
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">0</th>
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">1</th>
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">2</th>
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">3</th>
|
||||
<th style="padding: 8px; border: 1px solid #cbd5e1;">4</th>
|
||||
</tr>
|
||||
<tr style="background: white; font-weight: bold; color: var(--text-main);">
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1; background: #f1f5f9;">Werte (Waggons)</td>
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1;"><code>"Apfel"</code></td>
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1;"><code>"Banane"</code></td>
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1;"><code>"Kirsche"</code></td>
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1;"><code>"Dattel"</code></td>
|
||||
<td style="padding: 10px; border: 1px solid #cbd5e1;"><code>"Erdbeere"</code></td>
|
||||
</tr>
|
||||
<tr style="background: #f8fafc; color: var(--text-muted);">
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">Negativer Index</td>
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">-5</td>
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">-4</td>
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">-3</td>
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">-2</td>
|
||||
<td style="padding: 8px; border: 1px solid #cbd5e1;">-1</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Index-Zugriff</span>
|
||||
</div>
|
||||
<pre><span class="var">fruechte</span> = [<span class="str">"Apfel"</span>, <span class="str">"Banane"</span>, <span class="str">"Kirsche"</span>, <span class="str">"Dattel"</span>, <span class="str">"Erdbeere"</span>]
|
||||
|
||||
<span class="fn">print</span>(<span class="var">fruechte</span>[<span class="num">0</span>]) <span class="cm"># -> "Apfel" (Erstes Element)</span>
|
||||
<span class="fn">print</span>(<span class="var">fruechte</span>[<span class="num">2</span>]) <span class="cm"># -> "Kirsche" (Drittes Element)</span>
|
||||
<span class="fn">print</span>(<span class="var">fruechte</span>[-<span class="num">1</span>]) <span class="cm"># -> "Erdbeere" (Letztes Element)</span>
|
||||
<span class="fn">print</span>(<span class="var">fruechte</span>[-<span class="num">2</span>]) <span class="cm"># -> "Dattel" (Vorletztes Element)</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Slicing -->
|
||||
<section class="card">
|
||||
<h2>2. ✂️ Slicing: Teile einer Liste herausschneiden</h2>
|
||||
|
||||
<p>
|
||||
Mit dem Slice-Muster <code>liste[start:stop:step]</code> schneidest du beliebige Teilbereiche heraus.
|
||||
<strong>Wichtig:</strong> Der <code>stop</code>-Index ist immer <em>exklusiv</em> (wird nicht mitgenommen)!
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Slicing Beispiele</span>
|
||||
</div>
|
||||
<pre><span class="var">zahlen</span> = [<span class="num">10</span>, <span class="num">20</span>, <span class="num">30</span>, <span class="num">40</span>, <span class="num">50</span>, <span class="num">60</span>]
|
||||
|
||||
<span class="cm"># 1. Bereich von Index 1 bis vor Index 4:</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[<span class="num">1</span>:<span class="num">4</span>]) <span class="cm"># -> [20, 30, 40]</span>
|
||||
|
||||
<span class="cm"># 2. Vom Anfang bis vor Index 3:</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[:<span class="num">3</span>]) <span class="cm"># -> [10, 20, 30]</span>
|
||||
|
||||
<span class="cm"># 3. Ab Index 3 bis ganz zum Schluss:</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[<span class="num">3</span>:]) <span class="cm"># -> [40, 50, 60]</span>
|
||||
|
||||
<span class="cm"># 4. Alle Elemente ohne erstes und letztes:</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[<span class="num">1</span>:-<span class="num">1</span>]) <span class="cm"># -> [20, 30, 40, 50]</span>
|
||||
|
||||
<span class="cm"># 5. Jedes 2. Element (Schrittweite 2):</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[::<span class="num">2</span>]) <span class="cm"># -> [10, 30, 50]</span>
|
||||
|
||||
<span class="cm"># 6. Liste komplett rückwärts:</span>
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>[::-<span class="num">1</span>]) <span class="cm"># -> [60, 50, 40, 30, 20, 10]</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">💡 Slicing erzeugt immer eine NEUE Liste:</div>
|
||||
Wenn du <code>kopie = zahlen[:]</code> oder <code>rueckwaerts = zahlen[::-1]</code> schreibst, bleibt die Original-Liste völlig unverändert!
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Listen-Methoden & Funktionen -->
|
||||
<section class="card">
|
||||
<h2>3. 🛠️ Methoden & Eingebaute Funktionen</h2>
|
||||
|
||||
<p>Listen bieten praktische Werkzeuge, um Elemente zu verändern, zu durchsuchen und auszuwerten:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Listen manipulieren</span>
|
||||
</div>
|
||||
<pre><span class="var">tiere</span> = [<span class="str">"Hund"</span>, <span class="str">"Katze"</span>]
|
||||
|
||||
<span class="cm"># Am Ende anfügen:</span>
|
||||
<span class="var">tiere</span>.<span class="fn">append</span>(<span class="str">"Maus"</span>) <span class="cm"># -> ["Hund", "Katze", "Maus"]</span>
|
||||
|
||||
<span class="cm"># An bestimmter Stelle einfügen:</span>
|
||||
<span class="var">tiere</span>.<span class="fn">insert</span>(<span class="num">0</span>, <span class="str">"Papagei"</span>) <span class="cm"># -> ["Papagei", "Hund", "Katze", "Maus"]</span>
|
||||
|
||||
<span class="cm"># Letztes Element entfernen und zurückgeben:</span>
|
||||
<span class="var">raus</span> = <span class="var">tiere</span>.<span class="fn">pop</span>() <span class="cm"># raus = "Maus", Rest: ["Papagei", "Hund", "Katze"]</span>
|
||||
|
||||
<span class="cm"># Bestimmten Wert sicher mit 'in' prüfen und entfernen:</span>
|
||||
<span class="kw">if</span> <span class="str">"Katze"</span> <span class="kw">in</span> <span class="var">tiere</span>:
|
||||
<span class="var">tiere</span>.<span class="fn">remove</span>(<span class="str">"Katze"</span>) <span class="cm"># Entfernt "Katze"</span>
|
||||
|
||||
<span class="cm"># Sortieren & Umdrehen (in-place am Original):</span>
|
||||
<span class="var">tiere</span>.<span class="fn">sort</span>()
|
||||
<span class="var">tiere</span>.<span class="fn">reverse</span>()</pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Vorsicht bei .remove():</div>
|
||||
Wenn du <code>liste.remove("Etwas")</code> aufrufst und <code>"Etwas"</code> gar nicht in der Liste ist, stürzt dein Programm mit einem <code>ValueError</code> ab! Prüfe vorher immer mit <code>if "Etwas" in liste:</code>.
|
||||
</div>
|
||||
|
||||
<h3>Statistik & Rechnen mit Listen</h3>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">noten</span> = [<span class="num">1.0</span>, <span class="num">2.3</span>, <span class="num">1.7</span>, <span class="num">3.0</span>]
|
||||
|
||||
<span class="fn">print</span>(<span class="fn">len</span>(<span class="var">noten</span>)) <span class="cm"># -> 4 (Anzahl der Elemente)</span>
|
||||
<span class="fn">print</span>(<span class="fn">min</span>(<span class="var">noten</span>)) <span class="cm"># -> 1.0 (kleinste Zahl / beste Note)</span>
|
||||
<span class="fn">print</span>(<span class="fn">max</span>(<span class="var">noten</span>)) <span class="cm"># -> 3.0 (größte Zahl / schlechteste Note)</span>
|
||||
<span class="fn">print</span>(<span class="fn">sum</span>(<span class="var">noten</span>)) <span class="cm"># -> 8.0 (Summe)</span>
|
||||
<span class="var">schnitt</span> = <span class="fn">sum</span>(<span class="var">noten</span>) / <span class="fn">len</span>(<span class="var">noten</span>) <span class="cm"># -> 2.0 (Durchschnitt)</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Aufgabenliste -->
|
||||
<section class="card">
|
||||
<h2>4. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g07_listen_und_sequenzen/aufgabe.py</code> und löse die 5 TODOs:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7_1">
|
||||
<label for="t7_1" class="task-label">
|
||||
<strong>TODO 1 (<code>liste_umdrehen</code>):</strong> Gib eine neue umgedrehte Liste zurück, ohne das Original zu modifizieren.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7_2">
|
||||
<label for="t7_2" class="task-label">
|
||||
<strong>TODO 2 (<code>filtere_positive_zahlen</code>):</strong> Gib eine Liste zurück, die nur Zahlen <code>> 0</code> enthält.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7_3">
|
||||
<label for="t7_3" class="task-label">
|
||||
<strong>TODO 3 (<code>entferne_element</code>):</strong> Entferne das Element sicher mit <code>in</code> und <code>.remove()</code>. Gib <code>True</code> zurück wenn gefunden, sonst <code>False</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7_4">
|
||||
<label for="t7_4" class="task-label">
|
||||
<strong>TODO 4 (<code>mittlere_elemente</code>):</strong> Schneide erstes und letztes Element mit Slicing ab. Bei <code>len(liste) <= 2</code> gib <code>[]</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t7_5">
|
||||
<label for="t7_5" class="task-label">
|
||||
<strong>TODO 5 (<code>noten_durchschnitt_ohne_ausreisser</code>):</strong> Entferne aus einer Kopie Minimum und Maximum und berechne <code>sum / len</code>. Bei weniger als 3 Noten gib <code>0.0</code> zurück.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Element sicher entfernen)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">entferne_element</span>(<span class="var">liste</span>, <span class="var">element</span>):
|
||||
<span class="kw">if</span> <span class="var">element</span> <span class="kw">in</span> <span class="var">liste</span>:
|
||||
<span class="var">liste</span>.<span class="fn">remove</span>(<span class="var">element</span>)
|
||||
<span class="kw">return</span> <span class="kw">True</span>
|
||||
<span class="kw">return</span> <span class="kw">False</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 5 (Notenschnitt ohne Ausreißer)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">noten_durchschnitt_ohne_ausreisser</span>(<span class="var">noten</span>):
|
||||
<span class="kw">if</span> <span class="fn">len</span>(<span class="var">noten</span>) < <span class="num">3</span>:
|
||||
<span class="kw">return</span> <span class="num">0.0</span>
|
||||
<span class="var">kopie</span> = <span class="fn">list</span>(<span class="var">noten</span>)
|
||||
<span class="var">kopie</span>.<span class="fn">remove</span>(<span class="fn">min</span>(<span class="var">kopie</span>))
|
||||
<span class="var">kopie</span>.<span class="fn">remove</span>(<span class="fn">max</span>(<span class="var">kopie</span>))
|
||||
<span class="kw">return</span> <span class="fn">sum</span>(<span class="var">kopie</span>) / <span class="fn">len</span>(<span class="var">kopie</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 5. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. 🧪 Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal folgenden Befehl aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g06_funktionen_und_module/index.html" class="btn btn-secondary">← Zurück zu Kapitel G06</a>
|
||||
<a href="../g08_textverarbeitung_und_strings/index.html" class="btn">Weiter zu Kapitel G08 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
57
g07_listen_und_sequenzen/musterloesung.py
Normal file
57
g07_listen_und_sequenzen/musterloesung.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
Kapitel G07: Listen & Sequenzen – Musterlösung
|
||||
===============================================
|
||||
"""
|
||||
|
||||
|
||||
def liste_umdrehen(liste: list) -> list:
|
||||
"""Gibt eine neue umgedrehte Liste zurück."""
|
||||
return liste[::-1]
|
||||
|
||||
|
||||
def filtere_positive_zahlen(zahlen: list[float]) -> list[float]:
|
||||
"""Filtert alle Zahlen > 0 heraus."""
|
||||
return [z for z in zahlen if z > 0]
|
||||
|
||||
|
||||
def entferne_element(liste: list, element) -> bool:
|
||||
"""Entfernt ein Element sicher, falls es existiert."""
|
||||
if element in liste:
|
||||
liste.remove(element)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def mittlere_elemente(liste: list) -> list:
|
||||
"""Gibt alle Elemente ohne erstes und letztes Element zurück."""
|
||||
if len(liste) <= 2:
|
||||
return []
|
||||
return liste[1:-1]
|
||||
|
||||
|
||||
def noten_durchschnitt_ohne_ausreisser(noten: list[float]) -> float:
|
||||
"""Entfernt Minimum und Maximum und berechnet den arithmetischen Mittelwert."""
|
||||
if len(noten) < 3:
|
||||
return 0.0
|
||||
kopie = list(noten)
|
||||
kopie.remove(min(kopie))
|
||||
kopie.remove(max(kopie))
|
||||
return sum(kopie) / len(kopie)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_liste = [10, 20, 30, 40, 50]
|
||||
print("Original:", test_liste)
|
||||
print("Umgedreht:", liste_umdrehen(test_liste))
|
||||
|
||||
zahlen = [-5, 12, 0, -3, 42, 7]
|
||||
print("Positive Zahlen:", filtere_positive_zahlen(zahlen))
|
||||
|
||||
tiere = ["Hund", "Katze", "Maus"]
|
||||
erfolg = entferne_element(tiere, "Katze")
|
||||
print(f"Katze entfernt? {erfolg} -> Rest: {tiere}")
|
||||
|
||||
print("Mittlere Elemente:", mittlere_elemente([1, 2, 3, 4, 5]))
|
||||
|
||||
noten = [1.0, 2.0, 3.0, 4.0, 5.0]
|
||||
print(f"Notenschnitt ohne Ausreißer von {noten}: {noten_durchschnitt_ohne_ausreisser(noten)}")
|
||||
123
g07_listen_und_sequenzen/test_aufgabe.py
Normal file
123
g07_listen_und_sequenzen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import unittest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG07(unittest.TestCase):
|
||||
|
||||
def test_01_liste_umdrehen(self):
|
||||
"""Prüft, ob eine Liste umgedreht wird, ohne das Original zu verändern."""
|
||||
original = [1, 2, 3, 4, 5]
|
||||
kopie_check = list(original)
|
||||
ergebnis = aufgabe.liste_umdrehen(original)
|
||||
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
[5, 4, 3, 2, 1],
|
||||
"Fehler: liste_umdrehen([1, 2, 3, 4, 5]) sollte [5, 4, 3, 2, 1] liefern!"
|
||||
)
|
||||
self.assertEqual(
|
||||
original,
|
||||
kopie_check,
|
||||
"Fehler: Die Original-Liste darf durch liste_umdrehen nicht verändert werden!"
|
||||
)
|
||||
|
||||
# Leere Liste & Einzelelement
|
||||
self.assertEqual(aufgabe.liste_umdrehen([]), [], "Fehler bei leerer Liste!")
|
||||
self.assertEqual(aufgabe.liste_umdrehen(["A"]), ["A"], "Fehler bei einelementiger Liste!")
|
||||
|
||||
def test_02_filtere_positive_zahlen(self):
|
||||
"""Prüft das Filtern positiver Zahlen (Zahlen > 0)."""
|
||||
eingabe = [-10, 5.5, 0, -1, 42, 0.0, 7]
|
||||
ergebnis = aufgabe.filtere_positive_zahlen(eingabe)
|
||||
erwartet = [5.5, 42, 7]
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler: filtere_positive_zahlen({eingabe}) sollte {erwartet} liefern, war aber {ergebnis}!"
|
||||
)
|
||||
|
||||
# Nur negative / Nullen
|
||||
self.assertEqual(
|
||||
aufgabe.filtere_positive_zahlen([-5, -1, 0]),
|
||||
[],
|
||||
"Fehler: Bei nur negativen Zahlen und 0 muss das Ergebnis [] sein!"
|
||||
)
|
||||
|
||||
# Leere Liste
|
||||
self.assertEqual(aufgabe.filtere_positive_zahlen([]), [])
|
||||
|
||||
def test_03_entferne_element(self):
|
||||
"""Prüft das sichere Entfernen eines Elements aus einer Liste."""
|
||||
farben = ["Rot", "Grün", "Blau", "Gelb"]
|
||||
|
||||
# Vorhandenes Element entfernen
|
||||
erfolg = aufgabe.entferne_element(farben, "Grün")
|
||||
self.assertTrue(erfolg, "Fehler: entferne_element sollte True zurückgeben, wenn Element existiert!")
|
||||
self.assertEqual(farben, ["Rot", "Blau", "Gelb"], "Fehler: 'Grün' wurde nicht aus der Liste entfernt!")
|
||||
|
||||
# Nicht vorhandenes Element
|
||||
erfolg_fehlt = aufgabe.entferne_element(farben, "Schwarz")
|
||||
self.assertFalse(erfolg_fehlt, "Fehler: entferne_element sollte False zurückgeben, wenn Element nicht existiert!")
|
||||
self.assertEqual(farben, ["Rot", "Blau", "Gelb"], "Fehler: Liste darf sich bei fehlendem Element nicht ändern!")
|
||||
|
||||
# Mehrfache Vorkommen: nur das erste soll entfernt werden
|
||||
zahlen = [1, 2, 2, 3]
|
||||
aufgabe.entferne_element(zahlen, 2)
|
||||
self.assertEqual(zahlen, [1, 2, 3], "Fehler: Bei Duplikaten sollte nur das erste Vorkommen entfernt werden!")
|
||||
|
||||
def test_04_mittlere_elemente(self):
|
||||
"""Prüft das Extrahieren der mittleren Elemente (ohne erstes und letztes)."""
|
||||
self.assertEqual(
|
||||
aufgabe.mittlere_elemente([10, 20, 30, 40, 50]),
|
||||
[20, 30, 40],
|
||||
"Fehler bei [10, 20, 30, 40, 50]!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.mittlere_elemente(["A", "B", "C"]),
|
||||
["B"],
|
||||
"Fehler bei 3 Elementen!"
|
||||
)
|
||||
|
||||
# Randfälle: <= 2 Elemente
|
||||
self.assertEqual(aufgabe.mittlere_elemente([1, 2]), [], "Fehler: Liste mit 2 Elementen muss [] liefern!")
|
||||
self.assertEqual(aufgabe.mittlere_elemente([1]), [], "Fehler: Liste mit 1 Element muss [] liefern!")
|
||||
self.assertEqual(aufgabe.mittlere_elemente([]), [], "Fehler: Leere Liste muss [] liefern!")
|
||||
|
||||
def test_05_noten_durchschnitt_ohne_ausreisser(self):
|
||||
"""Prüft die Durchschnittsberechnung ohne Best- und Schlechtnote."""
|
||||
noten = [1.0, 2.0, 3.0, 4.0, 5.0]
|
||||
original_noten = list(noten)
|
||||
schnitt = aufgabe.noten_durchschnitt_ohne_ausreisser(noten)
|
||||
|
||||
self.assertAlmostEqual(
|
||||
schnitt,
|
||||
3.0,
|
||||
places=4,
|
||||
msg="Fehler: Notenschnitt für [1.0, 2.0, 3.0, 4.0, 5.0] ohne 1.0 und 5.0 sollte 3.0 sein!"
|
||||
)
|
||||
self.assertEqual(
|
||||
noten,
|
||||
original_noten,
|
||||
"Fehler: Die übergebene Liste 'noten' darf nicht mutiert werden!"
|
||||
)
|
||||
|
||||
# Weiteres Notenbeispiel
|
||||
noten2 = [5.0, 1.0, 2.0, 3.0] # min=1.0, max=5.0 -> rest=[2.0, 3.0] -> avg=2.5
|
||||
self.assertAlmostEqual(aufgabe.noten_durchschnitt_ohne_ausreisser(noten2), 2.5, places=4)
|
||||
|
||||
# Randfälle: weniger als 3 Noten
|
||||
self.assertEqual(aufgabe.noten_durchschnitt_ohne_ausreisser([1.0, 2.0]), 0.0)
|
||||
self.assertEqual(aufgabe.noten_durchschnitt_ohne_ausreisser([3.0]), 0.0)
|
||||
self.assertEqual(aufgabe.noten_durchschnitt_ohne_ausreisser([]), 0.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
127
g08_textverarbeitung_und_strings/README.md
Normal file
127
g08_textverarbeitung_und_strings/README.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# Kapitel G08: Textverarbeitung & Strings in Python 🔤✨
|
||||
|
||||
Willkommen im Kapitel **Textverarbeitung und Strings**! Strings (Zeichenketten) gehören zu den vielseitigsten Datentypen in Python. In diesem Kapitel lernst du alle wichtigen String-Methoden zur Bereinigung, Suche, Zerlegung und Formatierung kennen.
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ 1. Die Stempel-Analogie: Strings sind unveränderlich (immutable)!
|
||||
|
||||
Ein grundlegendes Konzept in Python: **Strings können nach ihrer Erstellung nicht mehr verändert werden!**
|
||||
|
||||
```python
|
||||
name = "python"
|
||||
# ❌ Das funktioniert NICHT und wirft einen TypeError:
|
||||
# name[0] = "P"
|
||||
|
||||
# ✅ Stattdessen erzeugt jede String-Methode einen NEUEN String:
|
||||
name = name.capitalize() # Erzeugt "Python" und weist es neu zu
|
||||
```
|
||||
|
||||
> 🖨️ **Die Stempel-Analogie:** Stell dir einen String wie gedruckten Text auf Papier vor. Du kannst die Buchstaben auf dem Papier nicht wegradieren. Jede String-Methode druckt stattdessen ein **frisches neues Blatt Papier** mit dem geänderten Text aus!
|
||||
|
||||
---
|
||||
|
||||
## 🧰 2. Das große String-Methoden Cheat-Sheet
|
||||
|
||||
Python stellt eine Fülle praktischer Methoden für Strings bereit:
|
||||
|
||||
### A. Groß- & Kleinschreibung
|
||||
```python
|
||||
text = "hallo welt"
|
||||
print(text.upper()) # -> "HALLO WELT" (alles GROSS)
|
||||
print(text.lower()) # -> "hallo welt" (alles klein)
|
||||
print(text.capitalize()) # -> "Hallo welt" (nur erstes Zeichen groß)
|
||||
print(text.title()) # -> "Hallo Welt" (jedes Wort groß)
|
||||
```
|
||||
|
||||
### B. Leerzeichen & Whitespace entfernen
|
||||
```python
|
||||
eingabe = " max_mustermann \n"
|
||||
print(eingabe.strip()) # -> "max_mustermann" (vorne & hinten bereinigt)
|
||||
print(eingabe.lstrip()) # -> "max_mustermann \n" (nur links)
|
||||
print(eingabe.rstrip()) # -> " max_mustermann" (nur rechts)
|
||||
```
|
||||
|
||||
### C. Suchen, Zählen & Ersetzen
|
||||
```python
|
||||
satz = "Python ist super und Python macht Spaß"
|
||||
|
||||
# Ersetzen:
|
||||
print(satz.replace("Python", "Coding"))
|
||||
# -> "Coding ist super und Coding macht Spaß"
|
||||
|
||||
# Vorkommen zählen:
|
||||
print(satz.count("Python")) # -> 2
|
||||
|
||||
# Position finden (-1 wenn nicht gefunden):
|
||||
print(satz.find("super")) # -> 11
|
||||
|
||||
# Anfang & Ende prüfen (liefert True / False):
|
||||
print(satz.startswith("Python")) # -> True
|
||||
print(satz.endswith("Spaß")) # -> True
|
||||
```
|
||||
|
||||
### D. Zerlegen (`.split`) & Zusammenfügen (`.join`)
|
||||
```python
|
||||
# 1. An Trennzeichen in eine Liste zerlegen:
|
||||
daten = "Max;Mustermann;18;Informatik"
|
||||
teile = daten.split(";")
|
||||
print(teile) # -> ["Max", "Mustermann", "18", "Informatik"]
|
||||
|
||||
# 2. Ohne Parameter zerlegt .split() an beliebigen Leerzeichen:
|
||||
woerter = " Python macht Spaß! ".split()
|
||||
print(woerter) # -> ["Python", "macht", "Spaß!"]
|
||||
|
||||
# 3. Eine Liste mit einem Trennzeichen zu einem String zusammenfügen:
|
||||
zutaten = ["Mehl", "Zucker", "Eier", "Milch"]
|
||||
kuchen = ", ".join(zutaten)
|
||||
print(kuchen) # -> "Mehl, Zucker, Eier, Milch"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✂️ 3. Strings sind Sequenzen (Index & Slicing)
|
||||
|
||||
Genau wie Listen kannst du auch auf einzelne Zeichen in Strings über deren Index und Slicing zugreifen:
|
||||
|
||||
```python
|
||||
wort = "Lagerregal"
|
||||
|
||||
print(wort[0]) # -> "L" (Erster Buchstabe)
|
||||
print(wort[-1]) # -> "l" (Letzter Buchstabe)
|
||||
print(wort[-4:]) # -> "egal" (Die letzten 4 Buchstaben)
|
||||
print(wort[::-1]) # -> "lagerregaL" (String umkehren!)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 4. Praxisbeispiel: CSV-Daten bereinigen & parsen
|
||||
|
||||
```python
|
||||
csv_zeile = " anna.meier@schule.at ; 1050 ; Wien ; 4A "
|
||||
|
||||
# 1. Zeile säubern und in Spalten zerlegen:
|
||||
spalten = [feld.strip() for feld in csv_zeile.split(";")]
|
||||
email, plz, stadt, klasse = spalten
|
||||
|
||||
print(f"E-Mail: {email.lower()}")
|
||||
print(f"Standort: {plz} {stadt.title()}")
|
||||
print(f"Klasse: {klasse}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `aufgabe.py` und implementiere die 5 Funktionen:
|
||||
|
||||
1. **`ist_palindrom(text)`**: Prüft, ob ein Text vorwärts wie rückwärts gleich ist (ignoriert Groß/Klein und Leerzeichen).
|
||||
2. **`zaehle_vokale(text)`**: Zählt alle Vokale (a, e, i, o, u, ä, ö, ü) im Text.
|
||||
3. **`bereinige_benutzernamen(name)`**: Entfernt Rand-Leerzeichen, konvertiert zu Kleinbuchstaben und ersetzt innere Leerzeichen durch `_`.
|
||||
4. **`woerter_zaehlen(text)`**: Nutzt `.split()`, um die Anzahl der Wörter zu ermitteln.
|
||||
5. **`maskiere_kreditkarte(nummer)`**: Ersetzt alle Zeichen außer den letzten 4 durch `*`.
|
||||
|
||||
### Testen deiner Lösung:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
140
g08_textverarbeitung_und_strings/aufgabe.py
Normal file
140
g08_textverarbeitung_und_strings/aufgabe.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
"""
|
||||
Kapitel G08: Textverarbeitung & Strings in Python (Schulabgleich 11.0)
|
||||
=====================================================================
|
||||
|
||||
In dieser Aufgabe lernst du die wichtigsten String-Methoden zur Textbereinigung,
|
||||
Suche, Formatierung und Analyse kennen.
|
||||
"""
|
||||
|
||||
|
||||
def ist_palindrom(text: str) -> bool:
|
||||
"""
|
||||
TODO 1: Prüft, ob ein Text ein Palindrom ist (von vorne und hinten
|
||||
gelesen exakt gleich lautet).
|
||||
|
||||
Regeln:
|
||||
- Groß- und Kleinschreibung wird ignoriert ('A' == 'a').
|
||||
- Leerzeichen werden ignoriert (z.B. "Dreh mal am Herd").
|
||||
|
||||
Beispiele:
|
||||
ist_palindrom("Anna") -> True
|
||||
ist_palindrom("Lagerregal") -> True
|
||||
ist_palindrom("Dreh mal am Herd") -> True
|
||||
ist_palindrom("Python") -> False
|
||||
|
||||
Tipp:
|
||||
1. Wandle den Text mit `.lower()` in Kleinbuchstaben um.
|
||||
2. Entferne Leerzeichen mit `.replace(" ", "")`.
|
||||
3. Vergleiche den bereinigten Text mit seiner Umkehrung: `bereinigt == bereinigt[::-1]`.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
def zaehle_vokale(text: str) -> int:
|
||||
"""
|
||||
TODO 2: Zählt die Anzahl aller Vokale im übergebenen Text.
|
||||
Als Vokale gelten: a, e, i, o, u sowie die Umlaute ä, ö, ü (Groß- und Kleinschreibung!).
|
||||
|
||||
Beispiele:
|
||||
zaehle_vokale("Python") -> 1 (nur 'o')
|
||||
zaehle_vokale("Käsebrot") -> 3 ('ä', 'e', 'o')
|
||||
zaehle_vokale("SCHÖNES Wetter") -> 4 ('Ö', 'E', 'e', 'e')
|
||||
zaehle_vokale("HTML") -> 0
|
||||
zaehle_vokale("Fly") -> 0
|
||||
|
||||
Tipp:
|
||||
Definiere eine Vokal-Menge oder Liste: `vokale = "aeiouäöü"`
|
||||
Wandle den Text in Kleinbuchstaben um (`text.lower()`) und zähle,
|
||||
wie viele Zeichen in `vokale` vorkommen.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
def bereinige_benutzernamen(name: str) -> str:
|
||||
"""
|
||||
TODO 3: Bereinigt einen eingegebenen Benutzernamen für ein Login-System.
|
||||
|
||||
Regeln:
|
||||
1. Führende und nachfolgende Leerzeichen werden entfernt (.strip()).
|
||||
2. Alle Buchstaben werden in Kleinbuchstaben umgewandelt (.lower()).
|
||||
3. Alle verbleibenden Leerzeichen zwischen Wörtern werden durch Unterstriche '_' ersetzt (.replace()).
|
||||
|
||||
Beispiele:
|
||||
bereinige_benutzernamen(" Max Mustermann ") -> "max_mustermann"
|
||||
bereinige_benutzernamen(" Super Coder 99 ") -> "super_coder_99"
|
||||
bereinige_benutzernamen("Lukas") -> "lukas"
|
||||
|
||||
Tipp:
|
||||
Du kannst String-Methoden verketten: `name.strip().lower().replace(" ", "_")`
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
def woerter_zaehlen(text: str) -> int:
|
||||
"""
|
||||
TODO 4: Zählt, wie viele Wörter im übergebenen Text vorkommen.
|
||||
- Mehrere Leerzeichen hintereinander zählen nicht als leere Wörter.
|
||||
- Ein leerer String "" enthält 0 Wörter.
|
||||
|
||||
Beispiele:
|
||||
woerter_zaehlen("Hallo Welt") -> 2
|
||||
woerter_zaehlen(" Python macht Spaß! ") -> 3
|
||||
woerter_zaehlen("") -> 0
|
||||
|
||||
Tipp:
|
||||
Verwende `.split()`. Ohne Parameter teilt es an beliebigen Leerzeichen
|
||||
und ignoriert doppelte Leerzeichen automatisch! `len(text.split())`
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
def maskiere_kreditkarte(nummer: str) -> str:
|
||||
"""
|
||||
TODO 5: Maskiert eine sensible Kartennummer oder ID, sodass nur die
|
||||
letzten 4 Zeichen sichtbar bleiben und alle vorherigen durch '*' ersetzt werden.
|
||||
|
||||
Regeln:
|
||||
- Hat die Nummer 4 oder weniger Zeichen, wird sie unverändert zurückgegeben.
|
||||
- Hat sie mehr als 4 Zeichen, werden alle bis auf die letzten 4 durch '*' ersetzt.
|
||||
|
||||
Beispiele:
|
||||
maskiere_kreditkarte("1234567812345678") -> "************5678"
|
||||
maskiere_kreditkarte("987654321") -> "*****4321"
|
||||
maskiere_kreditkarte("1234") -> "1234"
|
||||
maskiere_kreditkarte("99") -> "99"
|
||||
|
||||
Tipp:
|
||||
1. Wenn `len(nummer) <= 4`: `return nummer`
|
||||
2. Anzahl der Sterne: `anzahl_sterne = len(nummer) - 4`
|
||||
3. Die letzten 4 Zeichen: `letzte_vier = nummer[-4:]`
|
||||
4. Gib `("*" * anzahl_sterne) + letzte_vier` zurück.
|
||||
"""
|
||||
# Schreibe hier deinen Code für TODO 5:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Führe die Datei aus mit: python3 aufgabe.py)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("--- Teste deine String-Funktionen ---")
|
||||
|
||||
test_palindrom = "Dreh mal am Herd"
|
||||
print(f"Ist '{test_palindrom}' ein Palindrom (TODO 1)?", ist_palindrom(test_palindrom))
|
||||
|
||||
test_vokale = "Käsebrot mit Äpfeln"
|
||||
print(f"Vokale in '{test_vokale}' (TODO 2):", zaehle_vokale(test_vokale))
|
||||
|
||||
roher_name = " Max Mustermann 2026 "
|
||||
print(f"Bereinigter Name von '{roher_name}' (TODO 3):", bereinige_benutzernamen(roher_name))
|
||||
|
||||
text = " Python macht wirklich großen Spaß! "
|
||||
print(f"Wortanzahl (TODO 4):", woerter_zaehlen(text))
|
||||
|
||||
karte = "1234567812345678"
|
||||
print(f"Maskierte Karte '{karte}' (TODO 5):", maskiere_kreditkarte(karte))
|
||||
231
g08_textverarbeitung_und_strings/index.html
Normal file
231
g08_textverarbeitung_und_strings/index.html
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G08: Textverarbeitung & Strings in Python</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g07_listen_und_sequenzen/index.html">Kapitel G07</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G08</span>
|
||||
</nav>
|
||||
<div class="header-badge">Grundlagen G08 (Schulabgleich 11.0)</div>
|
||||
<h1>Textverarbeitung & Strings 🔤✨</h1>
|
||||
<p>Lerne, wie du Texte zerlegst, bereinigst, durchsuchst und formatierst – mit den mächtigen String-Methoden von Python.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Stempel-Analogie & Immutability -->
|
||||
<section class="card">
|
||||
<h2>1. 🏛️ Die Stempel-Analogie: Strings sind unveränderlich!</h2>
|
||||
|
||||
<p>
|
||||
In Python sind <strong>Strings (<code>str</code>) unveränderlich (immutable)</strong>. Das bedeutet:
|
||||
Sobald ein String erzeugt wurde, kann kein einzelner Buchstabe mehr ausgetauscht werden!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🖨️ Die Stempel- & Druck-Analogie:</div>
|
||||
<p>
|
||||
Stell dir einen String wie ein gedrucktes Dokument vor. Wenn du <code>text.upper()</code> oder <code>text.replace("a", "b")</code> aufrufst,
|
||||
wird nicht der Buchstabe auf dem Papier radiert.
|
||||
Stattdessen nimmt Python ein <strong>frisches, neues Blatt Papier</strong> und stempelt den modifizierten Text darauf!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Immutable Strings</span>
|
||||
</div>
|
||||
<pre><span class="var">name</span> = <span class="str">"python"</span>
|
||||
|
||||
<span class="cm"># ❌ Falsch: Einzelnes Zeichen überschreiben geht nicht!</span>
|
||||
<span class="cm"># name[0] = "P" -> TypeError: 'str' object does not support item assignment</span>
|
||||
|
||||
<span class="cm"># ✅ Richtig: Die Methode liefert einen NEUEN String zurück, den wir neu zuweisen:</span>
|
||||
<span class="var">name</span> = <span class="var">name</span>.<span class="fn">capitalize</span>() <span class="cm"># name ist jetzt "Python"</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Methoden Cheat-Sheet -->
|
||||
<section class="card">
|
||||
<h2>2. 🧰 Das große String-Methoden Cheat-Sheet</h2>
|
||||
|
||||
<p>Hier siehst du die wichtigsten Methoden für deine tägliche Textverarbeitung im Überblick:</p>
|
||||
|
||||
<h3>A. Groß- & Kleinschreibung</h3>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">t</span> = <span class="str">"hallo welt"</span>
|
||||
<span class="fn">print</span>(<span class="var">t</span>.<span class="fn">upper</span>()) <span class="cm"># -> "HALLO WELT" (alles GROSS)</span>
|
||||
<span class="fn">print</span>(<span class="var">t</span>.<span class="fn">lower</span>()) <span class="cm"># -> "hallo welt" (alles klein)</span>
|
||||
<span class="fn">print</span>(<span class="var">t</span>.<span class="fn">capitalize</span>()) <span class="cm"># -> "Hallo welt" (nur erstes Zeichen groß)</span>
|
||||
<span class="fn">print</span>(<span class="var">t</span>.<span class="fn">title</span>()) <span class="cm"># -> "Hallo Welt" (jedes Wort groß)</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>B. Leerzeichen bereinigen (.strip)</h3>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">roh</span> = <span class="str">" max_mustermann \n "</span>
|
||||
<span class="fn">print</span>(<span class="var">roh</span>.<span class="fn">strip</span>()) <span class="cm"># -> "max_mustermann" (entfernt Leerzeichen & Umbrüche an beiden Enden)</span>
|
||||
<span class="fn">print</span>(<span class="var">roh</span>.<span class="fn">lstrip</span>()) <span class="cm"># -> entfernt nur links</span>
|
||||
<span class="fn">print</span>(<span class="var">roh</span>.<span class="fn">rstrip</span>()) <span class="cm"># -> entfernt nur rechts</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>C. Suchen, Zählen & Ersetzen</h3>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">satz</span> = <span class="str">"Python ist super und Python macht Spaß"</span>
|
||||
|
||||
<span class="cm"># Ersetzen:</span>
|
||||
<span class="var">neu</span> = <span class="var">satz</span>.<span class="fn">replace</span>(<span class="str">"Python"</span>, <span class="str">"Coding"</span>) <span class="cm"># Ersetzt alle Vorkommen</span>
|
||||
|
||||
<span class="cm"># Zählen & Suchen:</span>
|
||||
<span class="fn">print</span>(<span class="var">satz</span>.<span class="fn">count</span>(<span class="str">"Python"</span>)) <span class="cm"># -> 2</span>
|
||||
<span class="fn">print</span>(<span class="var">satz</span>.<span class="fn">find</span>(<span class="str">"super"</span>)) <span class="cm"># -> Index 11 (-1 falls nicht vorhanden)</span>
|
||||
<span class="fn">print</span>(<span class="var">satz</span>.<span class="fn">startswith</span>(<span class="str">"Python"</span>)) <span class="cm"># -> True</span>
|
||||
<span class="fn">print</span>(<span class="var">satz</span>.<span class="fn">endswith</span>(<span class="str">"Spaß"</span>)) <span class="cm"># -> True</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>D. Zerlegen (.split) & Zusammenfügen (.join)</h3>
|
||||
<div class="code-container">
|
||||
<pre><span class="cm"># 1. An Trennzeichen zerlegen:</span>
|
||||
<span class="var">csv</span> = <span class="str">"Anna;17;Wien"</span>
|
||||
<span class="var">spalten</span> = <span class="var">csv</span>.<span class="fn">split</span>(<span class="str">";"</span>) <span class="cm"># -> ["Anna", "17", "Wien"]</span>
|
||||
|
||||
<span class="cm"># 2. Ohne Parameter zerlegt .split() an beliebigen Whitespaces:</span>
|
||||
<span class="var">woerter</span> = <span class="str">" Python macht Spaß "</span>.<span class="fn">split</span>()
|
||||
<span class="fn">print</span>(<span class="var">woerter</span>) <span class="cm"># -> ["Python", "macht", "Spaß"]</span>
|
||||
|
||||
<span class="cm"># 3. Liste wieder zu einem formatierten String verknüpfen:</span>
|
||||
<span class="var">liste</span> = [<span class="str">"Rot"</span>, <span class="str">"Grün"</span>, <span class="str">"Blau"</span>]
|
||||
<span class="var">farben_text</span> = <span class="str">", "</span>.<span class="fn">join</span>(<span class="var">liste</span>) <span class="cm"># -> "Rot, Grün, Blau"</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Praxisbeispiel Palindrom & Textbereinigung -->
|
||||
<section class="card">
|
||||
<h2>3. 🌟 Praxisbeispiel: Palindrom & Text-Bereinigung</h2>
|
||||
|
||||
<p>Ein Palindrom ist ein Text, der vorwärts wie rückwärts identisch ist (z.B. <em>"Dreh mal am Herd"</em>). Mit String-Methoden und Slicing ist die Prüfung ein Kinderspiel:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Palindrom-Prüfer</span>
|
||||
</div>
|
||||
<pre><span class="kw">def</span> <span class="fn">pruefe_palindrom</span>(<span class="var">text</span>):
|
||||
<span class="cm"># 1. Alles in Kleinbuchstaben umwandeln:</span>
|
||||
<span class="var">sauber</span> = <span class="var">text</span>.<span class="fn">lower</span>()
|
||||
<span class="cm"># 2. Leerzeichen entfernen:</span>
|
||||
<span class="var">sauber</span> = <span class="var">sauber</span>.<span class="fn">replace</span>(<span class="str">" "</span>, <span class="str">""</span>)
|
||||
<span class="cm"># 3. Mit der Umkehrung (Slicing [::-1]) vergleichen:</span>
|
||||
<span class="kw">return</span> <span class="var">sauber</span> == <span class="var">sauber</span>[::-<span class="num">1</span>]
|
||||
|
||||
<span class="fn">print</span>(<span class="fn">pruefe_palindrom</span>(<span class="str">"Anna"</span>)) <span class="cm"># -> True</span>
|
||||
<span class="fn">print</span>(<span class="fn">pruefe_palindrom</span>(<span class="str">"Dreh mal am Herd"</span>)) <span class="cm"># -> True</span>
|
||||
<span class="fn">print</span>(<span class="fn">pruefe_palindrom</span>(<span class="str">"Python"</span>)) <span class="cm"># -> False</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Aufgabenliste -->
|
||||
<section class="card">
|
||||
<h2>4. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g08_textverarbeitung_und_strings/aufgabe.py</code> und löse die 5 Aufgaben:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t8_1">
|
||||
<label for="t8_1" class="task-label">
|
||||
<strong>TODO 1 (<code>ist_palindrom</code>):</strong> Prüfe, ob ein Text von beiden Seiten gleich lautet (ignoriere Groß/Klein und Leerzeichen).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t8_2">
|
||||
<label for="t8_2" class="task-label">
|
||||
<strong>TODO 2 (<code>zaehle_vokale</code>):</strong> Zähle alle Vokale (a, e, i, o, u, ä, ö, ü) im Text unabhängig von Groß/Klein.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t8_3">
|
||||
<label for="t8_3" class="task-label">
|
||||
<strong>TODO 3 (<code>bereinige_benutzernamen</code>):</strong> Entferne Rand-Leerzeichen mit <code>.strip()</code>, mache alles lowercase und ersetze Leerzeichen durch <code>_</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t8_4">
|
||||
<label for="t8_4" class="task-label">
|
||||
<strong>TODO 4 (<code>woerter_zaehlen</code>):</strong> Ermittle die Wortanzahl mithilfe von <code>.split()</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t8_5">
|
||||
<label for="t8_5" class="task-label">
|
||||
<strong>TODO 5 (<code>maskiere_kreditkarte</code>):</strong> Ersetze alle Ziffern bis auf die letzten 4 durch <code>*</code> (z.B. <code>"************5678"</code>).
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Benutzernamen bereinigen)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">bereinige_benutzernamen</span>(<span class="var">name</span>):
|
||||
<span class="kw">return</span> <span class="var">name</span>.<span class="fn">strip</span>().<span class="fn">lower</span>().<span class="fn">replace</span>(<span class="str">" "</span>, <span class="str">"_"</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 5 (Kreditkarte maskieren)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">maskiere_kreditkarte</span>(<span class="var">nummer</span>):
|
||||
<span class="kw">if</span> <span class="fn">len</span>(<span class="var">nummer</span>) <= <span class="num">4</span>:
|
||||
<span class="kw">return</span> <span class="var">nummer</span>
|
||||
<span class="kw">return</span> <span class="str">"*"</span> * (<span class="fn">len</span>(<span class="var">nummer</span>) - <span class="num">4</span>) + <span class="var">nummer</span>[-<span class="num">4</span>:]</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 5. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. 🧪 Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal folgenden Befehl aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g07_listen_und_sequenzen/index.html" class="btn btn-secondary">← Zurück zu Kapitel G07</a>
|
||||
<a href="../g09_dictionaries_und_sets/index.html" class="btn">Weiter zu Kapitel G09 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
42
g08_textverarbeitung_und_strings/musterloesung.py
Normal file
42
g08_textverarbeitung_und_strings/musterloesung.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
Kapitel G08: Textverarbeitung & Strings – Musterlösung
|
||||
======================================================
|
||||
"""
|
||||
|
||||
|
||||
def ist_palindrom(text: str) -> bool:
|
||||
"""Prüft, ob text ein Palindrom ist (ignoriert Groß/Klein und Leerzeichen)."""
|
||||
bereinigt = text.lower().replace(" ", "")
|
||||
return bereinigt == bereinigt[::-1]
|
||||
|
||||
|
||||
def zaehle_vokale(text: str) -> int:
|
||||
"""Zählt Vokale inklusive deutscher Umlaute."""
|
||||
vokale = set("aeiouäöü")
|
||||
return sum(1 for c in text.lower() if c in vokale)
|
||||
|
||||
|
||||
def bereinige_benutzernamen(name: str) -> str:
|
||||
"""Strippt, wandelt in Kleinbuchstaben um und ersetzt Leerzeichen durch Unterstriche."""
|
||||
return name.strip().lower().replace(" ", "_")
|
||||
|
||||
|
||||
def woerter_zaehlen(text: str) -> int:
|
||||
"""Zählt Wörter anhand von Whitespace-Trennung."""
|
||||
return len(text.split())
|
||||
|
||||
|
||||
def maskiere_kreditkarte(nummer: str) -> str:
|
||||
"""Maskiert alle Zeichen bis auf die letzten 4 mit Sternchen."""
|
||||
if len(nummer) <= 4:
|
||||
return nummer
|
||||
return "*" * (len(nummer) - 4) + nummer[-4:]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Palindrom 'Anna':", ist_palindrom("Anna"))
|
||||
print("Palindrom 'Dreh mal am Herd':", ist_palindrom("Dreh mal am Herd"))
|
||||
print("Vokale 'Käsebrot':", zaehle_vokale("Käsebrot"))
|
||||
print("Benutzername ' Max Mustermann ':", bereinige_benutzernamen(" Max Mustermann "))
|
||||
print("Wörter 'Python macht Spaß':", woerter_zaehlen("Python macht Spaß"))
|
||||
print("Maskiert '1234567812345678':", maskiere_kreditkarte("1234567812345678"))
|
||||
97
g08_textverarbeitung_und_strings/test_aufgabe.py
Normal file
97
g08_textverarbeitung_und_strings/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import unittest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG08(unittest.TestCase):
|
||||
|
||||
def test_01_ist_palindrom(self):
|
||||
"""Prüft die Palindrom-Erkennung unter Berücksichtigung von Leerzeichen und Groß/Klein."""
|
||||
# Echte Palindrome
|
||||
self.assertTrue(aufgabe.ist_palindrom("Anna"), "'Anna' ist ein Palindrom!")
|
||||
self.assertTrue(aufgabe.ist_palindrom("Lagerregal"), "'Lagerregal' ist ein Palindrom!")
|
||||
self.assertTrue(aufgabe.ist_palindrom("Dreh mal am Herd"), "'Dreh mal am Herd' sollte True liefern!")
|
||||
self.assertTrue(aufgabe.ist_palindrom("Rentner"), "'Rentner' ist ein Palindrom!")
|
||||
self.assertTrue(aufgabe.ist_palindrom("A"), "Ein Buchstabe ist ein Palindrom!")
|
||||
self.assertTrue(aufgabe.ist_palindrom(""), "Leerer Text gilt als Palindrom!")
|
||||
|
||||
# Keine Palindrome
|
||||
self.assertFalse(aufgabe.ist_palindrom("Python"), "'Python' ist kein Palindrom!")
|
||||
self.assertFalse(aufgabe.ist_palindrom("Informatik"), "'Informatik' ist kein Palindrom!")
|
||||
self.assertFalse(aufgabe.ist_palindrom("Hallo Welt"), "'Hallo Welt' ist kein Palindrom!")
|
||||
|
||||
def test_02_zaehle_vokale(self):
|
||||
"""Prüft das Zählen von Vokalen inklusive Umlauten und Groß/Kleinschreibung."""
|
||||
self.assertEqual(aufgabe.zaehle_vokale("Python"), 1, "In 'Python' gibt es 1 Vokal ('o')!")
|
||||
self.assertEqual(aufgabe.zaehle_vokale("Käsebrot"), 3, "In 'Käsebrot' gibt es 3 Vokale ('ä', 'e', 'o')!")
|
||||
self.assertEqual(
|
||||
aufgabe.zaehle_vokale("SCHÖNES Wetter"),
|
||||
4,
|
||||
"In 'SCHÖNES Wetter' gibt es 4 Vokale ('Ö', 'E', 'e', 'e')!"
|
||||
)
|
||||
self.assertEqual(aufgabe.zaehle_vokale("Überflieger"), 5, "In 'Überflieger' gibt es 5 Vokale ('Ü', 'e', 'i', 'e', 'e')!")
|
||||
self.assertEqual(aufgabe.zaehle_vokale("HTML"), 0, "In 'HTML' gibt es 0 Vokale!")
|
||||
self.assertEqual(aufgabe.zaehle_vokale("Fly"), 0, "In 'Fly' gibt es 0 Vokale!")
|
||||
self.assertEqual(aufgabe.zaehle_vokale(""), 0, "Leerer String hat 0 Vokale!")
|
||||
|
||||
def test_03_bereinige_benutzernamen(self):
|
||||
"""Prüft die Bereinigung von Benutzernamen (strip, lowercase, Leerzeichen -> '_')."""
|
||||
self.assertEqual(
|
||||
aufgabe.bereinige_benutzernamen(" Max Mustermann "),
|
||||
"max_mustermann",
|
||||
"Fehler bei ' Max Mustermann '!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.bereinige_benutzernamen(" Super Coder 99 "),
|
||||
"super_coder_99",
|
||||
"Fehler bei ' Super Coder 99 '!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.bereinige_benutzernamen("LUKAS"),
|
||||
"lukas",
|
||||
"Fehler bei 'LUKAS'!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.bereinige_benutzernamen("anna"),
|
||||
"anna"
|
||||
)
|
||||
|
||||
def test_04_woerter_zaehlen(self):
|
||||
"""Prüft das Zählen von Wörtern bei verschiedenen Leerzeichen-Kombinationen."""
|
||||
self.assertEqual(aufgabe.woerter_zaehlen("Hallo Welt"), 2)
|
||||
self.assertEqual(
|
||||
aufgabe.woerter_zaehlen(" Python macht Spaß! "),
|
||||
3,
|
||||
"Mehrere Leerzeichen sollten ignoriert werden!"
|
||||
)
|
||||
self.assertEqual(aufgabe.woerter_zaehlen("EinWort"), 1)
|
||||
self.assertEqual(aufgabe.woerter_zaehlen(""), 0, "Leerer Text muss 0 Wörter liefern!")
|
||||
self.assertEqual(aufgabe.woerter_zaehlen(" "), 0, "Nur Leerzeichen müssen 0 Wörter liefern!")
|
||||
|
||||
def test_05_maskiere_kreditkarte(self):
|
||||
"""Prüft die Maskierung von Kartennummern / sensiblen Strings."""
|
||||
self.assertEqual(
|
||||
aufgabe.maskiere_kreditkarte("1234567812345678"),
|
||||
"************5678",
|
||||
"Fehler: 16-stellige Nummer muss 12 Sterne + letzte 4 Ziffern haben!"
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.maskiere_kreditkarte("987654321"),
|
||||
"*****4321",
|
||||
"Fehler: 9-stellige Nummer muss 5 Sterne + letzte 4 Ziffern haben!"
|
||||
)
|
||||
# Randfälle: <= 4 Zeichen
|
||||
self.assertEqual(aufgabe.maskiere_kreditkarte("1234"), "1234")
|
||||
self.assertEqual(aufgabe.maskiere_kreditkarte("99"), "99")
|
||||
self.assertEqual(aufgabe.maskiere_kreditkarte(""), "")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
169
g09_dictionaries_und_sets/README.md
Normal file
169
g09_dictionaries_und_sets/README.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
# Kapitel G09: Dictionaries & Sets (Mengen) 📖🎯
|
||||
|
||||
Schulabgleich: **Thema 15.0 (Dictionaries und Mengen)**
|
||||
|
||||
Herzlich willkommen zu Kapitel G09! In diesem Kapitel lernst du zwei unverzichtbare Datenstrukturen kennen, die in modernen Python-Programmen tagtäglich eingesetzt werden: **Dictionaries** (Schlüssel-Wert-Zuordnungen) und **Sets** (Mengen ohne Duplikate).
|
||||
|
||||
---
|
||||
|
||||
## 🗃️ 1. Dictionaries: Die Karteikasten-Analogie
|
||||
|
||||
Ein **Dictionary** (abgekürzt `dict`) speichert Daten als **Schlüssel-Wert-Paare** (`key: value`).
|
||||
|
||||
Stell dir einen klassischen **Karteikasten** oder ein **Wörterbuch** vor:
|
||||
- Wenn du nach dem Wort *"Schmetterling"* suchst (der **Key / Schlüssel**), findest du die englische Übersetzung *"Butterfly"* (der **Value / Wert**).
|
||||
- Während eine Python-Liste Elemente über einen numerischen Index (`liste[0]`, `liste[1]`) abruft, greift ein Dictionary über beliebige eindeutige Schlüssel (meist Texte oder Zahlen) zu!
|
||||
|
||||
```
|
||||
[ DICTIONARY: telefonbuch ]
|
||||
┌────────────────────────┬────────────────────────┐
|
||||
│ SCHLÜSSEL (Key) │ WERT (Value) │
|
||||
├────────────────────────┼────────────────────────┤
|
||||
│ "Anna" │ "0171-123456" │
|
||||
│ "Ben" │ "0160-987654" │
|
||||
│ "Clara" │ "0151-555666" │
|
||||
└────────────────────────┴────────────────────────┘
|
||||
```
|
||||
|
||||
### Grundlegende Syntax:
|
||||
```python
|
||||
# Dictionary erstellen:
|
||||
kontakt = {
|
||||
"name": "Anna",
|
||||
"alter": 23,
|
||||
"ort": "Berlin"
|
||||
}
|
||||
|
||||
# Zugriff über Schlüssel:
|
||||
print(kontakt["name"]) # "Anna"
|
||||
|
||||
# Neuen Eintrag hinzufügen oder bestehenden ändern:
|
||||
kontakt["email"] = "anna@example.com"
|
||||
kontakt["alter"] = 24
|
||||
|
||||
# Eintrag entfernen:
|
||||
del kontakt["ort"]
|
||||
# oder mit Rückgabewert:
|
||||
entfernter_wert = kontakt.pop("email")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ 2. Sicherer Datenzugriff: `dict[key]` vs. `dict.get(key, default)`
|
||||
|
||||
Ein häufiger Absturzgrund in Python ist der direkte Zugriff auf einen nicht existierenden Schlüssel:
|
||||
|
||||
```python
|
||||
benutzer = {"name": "Max"}
|
||||
|
||||
# 💥 ABSTURZ:
|
||||
print(benutzer["telefon"]) # KeyError: 'telefon'
|
||||
|
||||
# ✅ SICHER:
|
||||
telefon = benutzer.get("telefon", "Keine Nummer hinterlegt")
|
||||
print(telefon) # Gibt "Keine Nummer hinterlegt" aus, OHNE Absturz!
|
||||
```
|
||||
|
||||
> **Goldene Regel:** Wenn du nicht zu 100% sicher bist, ob ein Schlüssel im Dictionary vorkommt, nutze immer `.get()` mit einem sinnvollen Standardwert!
|
||||
|
||||
---
|
||||
|
||||
## 🔄 3. Über Dictionaries iterieren: `.keys()`, `.values()`, `.items()`
|
||||
|
||||
Python bietet drei praktische Methoden für Schleifen:
|
||||
|
||||
```python
|
||||
preise = {"Apfel": 0.80, "Banane": 1.20, "Mango": 2.50}
|
||||
|
||||
# 1. Nur Schlüssel durchlaufen:
|
||||
for frucht in preise.keys(): # oder einfach: for frucht in preise:
|
||||
print(frucht)
|
||||
|
||||
# 2. Nur Werte durchlaufen:
|
||||
for preis in preise.values():
|
||||
print(f"{preis:.2f} €")
|
||||
|
||||
# 3. Schlüssel UND Werte gleichzeitig (sehr nützlich!):
|
||||
for frucht, preis in preise.items():
|
||||
print(f"{frucht}: {preis:.2f} €")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎟️ 4. Sets (Mengen): Die Club-Türsteher-Analogie
|
||||
|
||||
Ein **Set** (`set`) ist eine ungeordnete Sammlung von **eindeutigen Elementen**.
|
||||
|
||||
Stell dir einen strengen **Club-Türsteher** vor:
|
||||
- Jeder Gast darf nur **ein einziges Mal** auf die Gästeliste.
|
||||
- Wenn jemand versucht, sich ein zweites Mal anzustellen, winkt der Türsteher ab: *"Du bist schon drin!"*
|
||||
- Im Club gibt es **keine feste Reihenfolge** (Sets haben keinen Index `set[0]`).
|
||||
|
||||
```python
|
||||
# Set mit geschweiften Klammern erstellen:
|
||||
farben = {"rot", "grün", "blau", "rot", "grün"}
|
||||
print(farben) # Ausgabe: {'rot', 'blau', 'grün'} (Duplikate automatisch entfernt!)
|
||||
|
||||
# Schnelle Zugehörigkeitsprüfung mit 'in' (extrem schnell in O(1)):
|
||||
if "rot" in farben:
|
||||
print("Rot ist dabei!")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧮 5. Mathematische Mengenoperationen mit Sets
|
||||
|
||||
Sets glänzen bei mathematischen Mengen-Vergleichen:
|
||||
|
||||
| Operation | Operator | Methode | Beschreibung |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Schnittmenge** | `A & B` | `A.intersection(B)` | Elemente, die in **beiden** Mengen vorkommen |
|
||||
| **Vereinigung** | `A \| B` | `A.union(B)` | Alle Elemente aus **beiden** Mengen (ohne Duplikate) |
|
||||
| **Differenz** | `A - B` | `A.difference(B)` | Elemente, die in A, aber **nicht** in B sind |
|
||||
| **Symmetrische Differenz** | `A ^ B` | `A.symmetric_difference(B)` | Elemente in A oder B, aber **nicht in beiden** |
|
||||
|
||||
```python
|
||||
schueler_kurs_a = {"Anna", "Ben", "Clara"}
|
||||
schueler_kurs_b = {"Ben", "Daniel", "Clara", "Emma"}
|
||||
|
||||
# Wer ist in beiden Kursen? (Schnittmenge)
|
||||
beide = schueler_kurs_a & schueler_kurs_b
|
||||
print("In beiden Kursen:", beide) # {'Ben', 'Clara'}
|
||||
|
||||
# Alle Schüler insgesamt? (Vereinigung)
|
||||
alle = schueler_kurs_a | schueler_kurs_b
|
||||
print("Alle Schüler:", alle) # {'Anna', 'Ben', 'Clara', 'Daniel', 'Emma'}
|
||||
|
||||
# Wer ist nur in Kurs A? (Differenz)
|
||||
nur_a = schueler_kurs_a - schueler_kurs_b
|
||||
print("Nur in Kurs A:", nur_a) # {'Anna'}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Häufige Stolperfallen
|
||||
|
||||
1. **Leeres Set vs. Leeres Dictionary:**
|
||||
- `{}` erzeugt ein **leeres Dictionary**, KEIN Set!
|
||||
- Um ein leeres Set zu erstellen, schreibe immer: `mein_set = set()`.
|
||||
2. **Keine veränderlichen Typen (Lists) als Keys oder Set-Elemente:**
|
||||
- Dictionaries-Schlüssel und Set-Elemente müssen **hashbar** (unveränderlich) sein (Strings, Zahlen, Tuples). Listen `[1, 2]` sind verboten (`TypeError: unhashable type: 'list'`).
|
||||
3. **Reihenfolge bei Sets:**
|
||||
- Sets garantieren **keine** feste Reihenfolge. Wenn du Duplikate aus einer Liste entfernen und dabei die Reihenfolge beibehalten willst, musst du dir mit einer Hilfsmenge (`seen = set()`) und einer Ergebnisliste behelfen.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne `g09_dictionaries_und_sets/aufgabe.py` und implementiere:
|
||||
|
||||
1. **TODO 1 (`woerter_haeufigkeit`):** Zähle die Häufigkeit jedes Wortes in einem Text (in Kleinbuchstaben, ohne Satzzeichen).
|
||||
2. **TODO 2 (`telefonbuch_suche`):** Suche sicher mit `.get()` eine Nummer im Telefonbuch (Rückgabe: Nummer oder `"Nicht gefunden"`).
|
||||
3. **TODO 3 (`gemeinsame_interessen`):** Finde die Hobbys, die zwei Personen gemeinsam haben (Schnittmenge `&`).
|
||||
4. **TODO 4 (`entferne_duplikate_behalte_reihenfolge`):** Filtere Duplikate aus einer Liste, behalte die Reihenfolge des ersten Auftretens bei.
|
||||
|
||||
### Testen:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
Sobald alle 9 Tests mit `OK` durchlaufen, bist du bereit für Kapitel G10!
|
||||
137
g09_dictionaries_und_sets/aufgabe.py
Normal file
137
g09_dictionaries_und_sets/aufgabe.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
"""
|
||||
Kapitel G09: Dictionaries & Sets (Mengen) – Aufgabenblatt
|
||||
=========================================================
|
||||
Schulabgleich: Thema 15.0 (Dictionaries und Mengen)
|
||||
|
||||
In diesem Kapitel lernst du zwei der wichtigsten Datenstrukturen in Python kennen:
|
||||
1. Dictionaries (Schlüssel-Wert-Paare wie im Wörterbuch oder Telefonbuch)
|
||||
2. Sets (Mengen von eindeutigen Elementen ohne Duplikate)
|
||||
|
||||
Bearbeite die Aufgaben von TODO 1 bis TODO 4.
|
||||
Überprüfe deine Lösung im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
from typing import List, Dict, Set
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Wörter-Häufigkeitszähler
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'woerter_haeufigkeit(text: str) -> dict[str, int]'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Wandle den gesamten Text in Kleinbuchstaben um (.lower()).
|
||||
# 2. Entferne gängige Satzzeichen (.,!?;:) aus dem Text oder bereinige die Wörter.
|
||||
# 3. Zerlege den Text in einzelne Wörter (.split()).
|
||||
# 4. Zähle mit einem Dictionary, wie oft jedes Wort vorkommt.
|
||||
# 5. Gib das fertige Dictionary {wort: anzahl} zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# text = "Apfel Banane Apfel Birne Banane Apfel"
|
||||
# Ergebnis: {"apfel": 3, "banane": 2, "birne": 1}
|
||||
# ==============================================================================
|
||||
|
||||
def woerter_haeufigkeit(text: str) -> Dict[str, int]:
|
||||
"""Zählt die Häufigkeit aller Wörter in einem gegebenen Text (case-insensitive)."""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Telefonbuch-Suche mit .get()
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'telefonbuch_suche(telefonbuch: dict[str, str], name: str) -> str'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Suche im Dictionary 'telefonbuch' nach dem Schlüssel 'name'.
|
||||
# 2. Verwende dafür die sichere Methode .get(key, standardwert), um einen KeyError
|
||||
# zu vermeiden!
|
||||
# 3. Wenn der Name existiert, gib die zugehörige Telefonnummer zurück.
|
||||
# 4. Wenn der Name NICHT existiert, gib den Text "Nicht gefunden" zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# buch = {"Anna": "0171-123456", "Ben": "0160-987654"}
|
||||
# telefonbuch_suche(buch, "Anna") -> "0171-123456"
|
||||
# telefonbuch_suche(buch, "Clara") -> "Nicht gefunden"
|
||||
# ==============================================================================
|
||||
|
||||
def telefonbuch_suche(telefonbuch: Dict[str, str], name: str) -> str:
|
||||
"""Sucht eine Telefonnummer im Telefonbuch mit sicherer .get() Abfrage."""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Gemeinsame Interessen (Mengenoperation Schnittmenge)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'gemeinsame_interessen(person_a_hobbys: set, person_b_hobbys: set) -> set'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Die Funktion erhält zwei Mengen (Sets) mit Hobbys von zwei Personen.
|
||||
# 2. Ermittle alle Hobbys, die BEIDE Personen gemeinsam haben (Schnittmenge / Intersection).
|
||||
# 3. Nutze entweder den Mengen-Operator '&' oder die Methode '.intersection()'.
|
||||
# 4. Gib das resultierende Set zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# a = {"Gaming", "Klettern", "Musik"}
|
||||
# b = {"Kochen", "Gaming", "Musik", "Lesen"}
|
||||
# gemeinsame_interessen(a, b) -> {"Gaming", "Musik"}
|
||||
# ==============================================================================
|
||||
|
||||
def gemeinsame_interessen(person_a_hobbys: Set[str], person_b_hobbys: Set[str]) -> Set[str]:
|
||||
"""Ermittelt die Schnittmenge der Hobbys zweier Personen."""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Duplikate entfernen & Reihenfolge beibehalten
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'entferne_duplikate_behalte_reihenfolge(liste: list) -> list'.
|
||||
#
|
||||
# Problem: Ein normales 'set(liste)' entfernt Duplikate, verliert aber die Reihenfolge!
|
||||
# Anforderungen:
|
||||
# 1. Entferne alle doppelten Elemente aus der übergebenen Liste.
|
||||
# 2. Die ursprüngliche Reihenfolge des ERSTEN Auftretens der Elemente muss erhalten bleiben.
|
||||
# 3. Nutze z.B. ein 'seen = set()', um bereits gesehene Elemente blitzschnell nachzuschlagen,
|
||||
# und füge neue Elemente einer Ergebnisliste hinzu.
|
||||
# 4. Gib die bereinigte Liste zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# eingabe = [1, 3, 2, 3, 1, 4, 2, 5]
|
||||
# Ergebnis: [1, 3, 2, 4, 5]
|
||||
# ==============================================================================
|
||||
|
||||
def entferne_duplikate_behalte_reihenfolge(liste: list) -> list:
|
||||
"""Entfernt Duplikate aus einer Liste unter Beibehaltung der Reihenfolge."""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Du kannst diese Datei direkt mit 'python3 aufgabe.py' ausführen)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("--- 📚 Testlauf: Dictionaries & Sets ---")
|
||||
|
||||
# Test TODO 1
|
||||
beispiel_text = "Python ist super. Python macht Spaß! Ist Python leicht? Ja!"
|
||||
haeufigkeiten = woerter_haeufigkeit(beispiel_text)
|
||||
print("Wort-Häufigkeiten:", haeufigkeiten)
|
||||
|
||||
# Test TODO 2
|
||||
tbuch = {"Alice": "0151-111111", "Bob": "0172-222222"}
|
||||
print("Suche Alice:", telefonbuch_suche(tbuch, "Alice"))
|
||||
print("Suche Charlie:", telefonbuch_suche(tbuch, "Charlie"))
|
||||
|
||||
# Test TODO 3
|
||||
hobbys_1 = {"Fotografie", "Reisen", "Schwimmen", "Python"}
|
||||
hobbys_2 = {"Kochen", "Python", "Reisen", "Yoga"}
|
||||
print("Gemeinsame Hobbys:", gemeinsame_interessen(hobbys_1, hobbys_2))
|
||||
|
||||
# Test TODO 4
|
||||
tiere_mit_duplikaten = ["Katze", "Hund", "Katze", "Maus", "Hund", "Hamster"]
|
||||
eindeutige_tiere = entferne_duplikate_behalte_reihenfolge(tiere_mit_duplikaten)
|
||||
print("Ohne Duplikate (Reihenfolge fix):", eindeutige_tiere)
|
||||
305
g09_dictionaries_und_sets/index.html
Normal file
305
g09_dictionaries_und_sets/index.html
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G09: Dictionaries & Sets</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g08_textverarbeitung_und_strings/index.html">← Kapitel G08</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G09</span>
|
||||
<span>›</span>
|
||||
<a href="../g10_comprehensions_datum_algorithmen/index.html">Kapitel G10 →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel G09 • Schulabgleich 15.0</div>
|
||||
<h1>Dictionaries & Sets: Schlüssel, Werte & Mengen 🗃️✨</h1>
|
||||
<p>Lerne, wie du Daten in Schlüssel-Wert-Paaren organisierst, blitzschnell nachschlägst und mit mathematischen Mengen Duplikate eliminierst.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. Dictionaries: Die Karteikasten-Analogie -->
|
||||
<section class="card">
|
||||
<h2>1. Was ist ein Dictionary? (Die Karteikasten-Analogie)</h2>
|
||||
|
||||
<p>
|
||||
Bisher hast du Daten oft in <strong>Listen</strong> gespeichert. Bei einer Liste greifst du über eine Zahl (den Index <code>0, 1, 2, ...</code>) auf Einträge zu.
|
||||
Aber was machst du, wenn du eine Telefonnummer zu einem <em>Namen</em> suchst oder eine deutsche Übersetzung zu einem <em>englischen Wort</em>?
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🗃️ Die Karteikasten- & Wörterbuch-Analogie:</div>
|
||||
<p>Ein <strong>Dictionary</strong> (Wörterbuch) funktioniert wie ein echter Karteikasten:</p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li>Vorne auf der Karteikarte steht das <strong>Stichwort (der Key / Schlüssel)</strong>, z.B. <code>"Anna"</code>.</li>
|
||||
<li>Auf der Rückseite steht die eigentliche <strong>Information (der Value / Wert)</strong>, z.B. <code>"0171-123456"</code>.</li>
|
||||
<li>Du musst nicht alle Karten von vorne bis hinten durchblättern – Python springt <strong>sofort in Lichtgeschwindigkeit</strong> zum gesuchten Schlüssel!</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Dictionary Grundlagen</span>
|
||||
</div>
|
||||
<pre><span class="cm"># 1. Dictionary erstellen mit geschweiften Klammern {key: value}:</span>
|
||||
<span class="var">kontakt</span> = {
|
||||
<span class="str">"name"</span>: <span class="str">"Anna"</span>,
|
||||
<span class="str">"alter"</span>: <span class="num">23</span>,
|
||||
<span class="str">"beruf"</span>: <span class="str">"Entwicklerin"</span>
|
||||
}
|
||||
|
||||
<span class="cm"># 2. Wert über Schlüssel abrufen:</span>
|
||||
<span class="fn">print</span>(<span class="var">kontakt</span>[<span class="str">"name"</span>]) <span class="cm"># Gibt "Anna" aus</span>
|
||||
|
||||
<span class="cm"># 3. Eintrag hinzufügen oder verändern:</span>
|
||||
<span class="var">kontakt</span>[<span class="str">"stadt"</span>] = <span class="str">"Berlin"</span> <span class="cm"># Neu hinzugefügt</span>
|
||||
<span class="var">kontakt</span>[<span class="str">"alter"</span>] = <span class="num">24</span> <span class="cm"># Wert aktualisiert</span>
|
||||
|
||||
<span class="cm"># 4. Eintrag löschen:</span>
|
||||
<span class="kw">del</span> <span class="var">kontakt</span>[<span class="str">"beruf"</span>] <span class="cm"># Entfernt den Schlüssel "beruf"</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Sicherer Zugriff mit .get() & Dict-Methoden -->
|
||||
<section class="card">
|
||||
<h2>2. Sicherer Datenzugriff mit <code>.get()</code> & Iteration</h2>
|
||||
|
||||
<p>
|
||||
Greifst du auf einen Schlüssel zu, den es im Dictionary nicht gibt, stürzt dein Programm mit einem gefürchteten <code>KeyError</code> ab!
|
||||
</p>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">🛡️ Die Lebensversicherung: <code>dict.get(key, standardwert)</code></div>
|
||||
Verwende <code>.get()</code>, wenn du nicht sicher weißt, ob der Schlüssel existiert. Statt abzustürzen, liefert Python einen sicheren Standardwert zurück!
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Vergleich: dict[key] vs dict.get()</span>
|
||||
</div>
|
||||
<pre><span class="var">user</span> = {<span class="str">"username"</span>: <span class="str">"coder99"</span>}
|
||||
|
||||
<span class="cm"># ❌ Riskant: Programm stürzt bei fehlendem Key ab!</span>
|
||||
<span class="cm"># print(user["email"]) # 💥 KeyError: 'email'</span>
|
||||
|
||||
<span class="cm"># ✅ Sicher: Liefert Fallback-Wert ohne Absturz!</span>
|
||||
<span class="var">email</span> = <span class="var">user</span>.<span class="fn">get</span>(<span class="str">"email"</span>, <span class="str">"Keine E-Mail angegeben"</span>)
|
||||
<span class="fn">print</span>(<span class="var">email</span>) <span class="cm"># Ausgabe: Keine E-Mail angegeben</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>Praktische Methoden: <code>.keys()</code>, <code>.values()</code> und <code>.items()</code></h3>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Schleifen über Dictionaries</span>
|
||||
</div>
|
||||
<pre><span class="var">preise</span> = {<span class="str">"Kaffee"</span>: <span class="num">3.50</span>, <span class="str">"Croissant"</span>: <span class="num">2.20</span>, <span class="str">"Tee"</span>: <span class="num">2.80</span>}
|
||||
|
||||
<span class="cm"># Schlüssel und Werte gleichzeitig durchlaufen mit .items():</span>
|
||||
<span class="kw">for</span> <span class="var">produkt</span>, <span class="var">preis</span> <span class="kw">in</span> <span class="var">preise</span>.<span class="fn">items</span>():
|
||||
<span class="fn">print</span>(<span class="str">f"{produkt} kostet {preis:.2f} €"</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 3. Sets: Die Club-Türsteher-Analogie -->
|
||||
<section class="card">
|
||||
<h2>3. Was ist ein Set (Menge)? (Die Club-Türsteher-Analogie)</h2>
|
||||
|
||||
<p>
|
||||
Ein <strong>Set</strong> (Menge) ist eine Sammlung von Elementen mit zwei besonderen Superkräften:
|
||||
<strong>1. Keine Duplikate erlaubt</strong> und <strong>2. Extrem schnelle Suche (in O(1))</strong>.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🚪 Die Club-Türsteher-Analogie:</div>
|
||||
<p>
|
||||
Stell dir einen Club vor, in dem jeder Gast genau <strong>einmal</strong> auf die Gästeliste darf:
|
||||
</p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li>Versucht jemand doppelt hineinzugehen, ignoriert der Türsteher den zweiten Versuch einfach.</li>
|
||||
<li>Es gibt im Club keine feste Sitzordnung (Sets sind <em>ungeordnet</em> und haben keinen Index wie <code>set[0]</code>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Sets erstellen und Duplikate filtern</span>
|
||||
</div>
|
||||
<pre><span class="cm"># Set erstellen (Duplikate fallen automatisch weg):</span>
|
||||
<span class="var">zahlen</span> = {<span class="num">1</span>, <span class="num">2</span>, <span class="num">2</span>, <span class="num">3</span>, <span class="num">3</span>, <span class="num">3</span>, <span class="num">4</span>}
|
||||
<span class="fn">print</span>(<span class="var">zahlen</span>) <span class="cm"># Ausgabe: {1, 2, 3, 4}</span>
|
||||
|
||||
<span class="cm"># Blitzschnelle Überprüfung mit 'in':</span>
|
||||
<span class="kw">if</span> <span class="num">3</span> <span class="kw">in</span> <span class="var">zahlen</span>:
|
||||
<span class="fn">print</span>(<span class="str">"3 ist in der Menge enthalten!"</span>)
|
||||
|
||||
<span class="cm"># ⚠️ Achtung beim leeren Set:</span>
|
||||
<span class="var">leeres_dict</span> = {} <span class="cm"># Erzeugt ein leeres Dictionary!</span>
|
||||
<span class="var">leeres_set</span> = <span class="fn">set</span>() <span class="cm"># ✅ So erstellst du ein leeres Set!</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>Mengenoperationen im Überblick</h3>
|
||||
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 15px 0;">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light); text-align: left;">
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Operation</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Operator</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Methode</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Bedeutung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Schnittmenge (Intersection)</strong></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A & B</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A.intersection(B)</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Gemeinsame Elemente beider Mengen</td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Vereinigung (Union)</strong></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A | B</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A.union(B)</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Alle Elemente aus A und B zusammen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Differenz</strong></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A - B</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>A.difference(B)</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Elemente in A, die NICHT in B vorkommen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- 4. Vollständiges Praxisbeispiel -->
|
||||
<section class="card">
|
||||
<h2>4. 🌟 Vollständiges Praxisbeispiel: Wörter-Zähler</h2>
|
||||
|
||||
<p>Hier siehst du, wie man mit Dictionaries Wort-Häufigkeiten in Texten ermittelt:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Python: Wort-Häufigkeiten zählen</span>
|
||||
</div>
|
||||
<pre><span class="kw">def</span> <span class="fn">zaehle_woerter</span>(<span class="var">text</span>):
|
||||
<span class="var">haeufigkeit</span> = {}
|
||||
<span class="var">woerter</span> = <span class="var">text</span>.<span class="fn">lower</span>().<span class="fn">split</span>()
|
||||
|
||||
<span class="kw">for</span> <span class="var">wort</span> <span class="kw">in</span> <span class="var">woerter</span>:
|
||||
<span class="cm"># Wenn das Wort noch nicht im Dict ist, startet der Zähler bei 0:</span>
|
||||
<span class="var">haeufigkeit</span>[<span class="var">wort</span>] = <span class="var">haeufigkeit</span>.<span class="fn">get</span>(<span class="var">wort</span>, <span class="num">0</span>) + <span class="num">1</span>
|
||||
|
||||
<span class="kw">return</span> <span class="var">haeufigkeit</span>
|
||||
|
||||
<span class="var">beispiel</span> = <span class="str">"Python macht Spaß und Python ist mächtig"</span>
|
||||
<span class="fn">print</span>(<span class="fn">zaehle_woerter</span>(<span class="var">beispiel</span>))
|
||||
<span class="cm"># Ausgabe: {'python': 2, 'macht': 1, 'spaß': 1, 'und': 1, 'ist': 1, 'mächtig': 1}</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. Aufgaben & Checkliste -->
|
||||
<section class="card">
|
||||
<h2>5. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g09_dictionaries_und_sets/aufgabe.py</code> und bearbeite die folgenden 4 Aufgaben:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1 (<code>woerter_haeufigkeit</code>):</strong> Bereinige den Text von Satzzeichen, wandle ihn in Kleinbuchstaben um und zähle, wie oft jedes Wort vorkommt.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2 (<code>telefonbuch_suche</code>):</strong> Verwende <code>.get()</code>, um eine Telefonnummer sicher abzufragen (liefert <code>"Nicht gefunden"</code> bei unbekanntem Namen).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3 (<code>gemeinsame_interessen</code>):</strong> Finde mit der Schnittmenge (<code>&</code>) die Hobbys, die zwei Personen gemeinsam teilen.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4 (<code>entferne_duplikate_behalte_reihenfolge</code>):</strong> Entferne doppelte Elemente aus einer Liste, ohne die ursprüngliche Reihenfolge zu verändern (Tipp: Hilfsmenge <code>seen = set()</code>).
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 1 (Satzzeichen entfernen & Zählen)</summary>
|
||||
<div class="details-content">
|
||||
<p>Du kannst Satzzeichen mit <code>replace()</code> durch Leerzeichen ersetzen und dann mit <code>.get(wort, 0) + 1</code> zählen:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">bereinigt</span> = <span class="var">text</span>.<span class="fn">lower</span>()
|
||||
<span class="kw">for</span> <span class="var">zeichen</span> <span class="kw">in</span> <span class="str">".,!?;:()\"'"</span>:
|
||||
<span class="var">bereinigt</span> = <span class="var">bereinigt</span>.<span class="fn">replace</span>(<span class="var">zeichen</span>, <span class="str">" "</span>)
|
||||
<span class="var">woerter</span> = <span class="var">bereinigt</span>.<span class="fn">split</span>()</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 4 (Reihenfolge bei Duplikaten behalten)</summary>
|
||||
<div class="details-content">
|
||||
<p>Nutze eine Liste für das Ergebnis und ein Set zum Merken bereits gesehener Elemente:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">seen</span> = <span class="fn">set</span>()
|
||||
<span class="var">ergebnis</span> = []
|
||||
<span class="kw">for</span> <span class="var">element</span> <span class="kw">in</span> <span class="var">liste</span>:
|
||||
<span class="kw">if</span> <span class="var">element</span> <span class="kw">not in</span> <span class="var">seen</span>:
|
||||
<span class="var">seen</span>.<span class="fn">add</span>(<span class="var">element</span>)
|
||||
<span class="var">ergebnis</span>.<span class="fn">append</span>(<span class="var">element</span>)
|
||||
<span class="kw">return</span> <span class="var">ergebnis</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 6. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>6. 🧪 Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal die automatische Test-Suite aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g08_textverarbeitung_und_strings/index.html" class="btn btn-secondary">← Zurück zu Kapitel G08</a>
|
||||
<a href="../g10_comprehensions_datum_algorithmen/index.html" class="btn">Weiter zu Kapitel G10: Comprehensions & Algorithmen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
75
g09_dictionaries_und_sets/musterloesung.py
Normal file
75
g09_dictionaries_und_sets/musterloesung.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
Kapitel G09: Dictionaries & Sets (Mengen) – Musterlösung
|
||||
=========================================================
|
||||
Schulabgleich: Thema 15.0 (Dictionaries und Mengen)
|
||||
|
||||
Hier findest du die vollständige Musterlösung zu allen Aufgaben.
|
||||
"""
|
||||
|
||||
from typing import List, Dict, Set
|
||||
|
||||
|
||||
# TODO 1: Wörter-Häufigkeitszähler
|
||||
def woerter_haeufigkeit(text: str) -> Dict[str, int]:
|
||||
"""Zählt die Häufigkeit aller Wörter in einem gegebenen Text (case-insensitive)."""
|
||||
# 1. Satzzeichen entfernen und Text in Kleinbuchstaben umwandeln
|
||||
satzzeichen = ".,!?;:()\"'[]{}<>"
|
||||
bereinigter_text = text.lower()
|
||||
for z in satzzeichen:
|
||||
bereinigter_text = bereinigter_text.replace(z, " ")
|
||||
|
||||
# 2. In Wörter zerlegen
|
||||
woerter = bereinigter_text.split()
|
||||
|
||||
# 3. Häufigkeiten zählen
|
||||
haeufigkeit: Dict[str, int] = {}
|
||||
for wort in woerter:
|
||||
haeufigkeit[wort] = haeufigkeit.get(wort, 0) + 1
|
||||
|
||||
return haeufigkeit
|
||||
|
||||
|
||||
# TODO 2: Telefonbuch-Suche mit .get()
|
||||
def telefonbuch_suche(telefonbuch: Dict[str, str], name: str) -> str:
|
||||
"""Sucht eine Telefonnummer im Telefonbuch mit sicherer .get() Abfrage."""
|
||||
return telefonbuch.get(name, "Nicht gefunden")
|
||||
|
||||
|
||||
# TODO 3: Gemeinsame Interessen (Mengenoperation Schnittmenge)
|
||||
def gemeinsame_interessen(person_a_hobbys: Set[str], person_b_hobbys: Set[str]) -> Set[str]:
|
||||
"""Ermittelt die Schnittmenge der Hobbys zweier Personen."""
|
||||
return person_a_hobbys & person_b_hobbys
|
||||
|
||||
|
||||
# TODO 4: Duplikate entfernen & Reihenfolge beibehalten
|
||||
def entferne_duplikate_behalte_reihenfolge(liste: list) -> list:
|
||||
"""Entfernt Duplikate aus einer Liste unter Beibehaltung der Reihenfolge."""
|
||||
seen = set()
|
||||
ergebnis = []
|
||||
for element in liste:
|
||||
if element not in seen:
|
||||
seen.add(element)
|
||||
ergebnis.append(element)
|
||||
return ergebnis
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("--- 📚 Musterlösung G09: Dictionaries & Sets ---")
|
||||
|
||||
# 1. Wörter-Häufigkeit
|
||||
text = "Python ist super. Python macht Spaß! Ist Python leicht? Ja!"
|
||||
print("Häufigkeiten:", woerter_haeufigkeit(text))
|
||||
|
||||
# 2. Telefonbuch
|
||||
buch = {"Anna": "0171-123456", "Ben": "0160-987654"}
|
||||
print("Suche Anna:", telefonbuch_suche(buch, "Anna"))
|
||||
print("Suche Clara:", telefonbuch_suche(buch, "Clara"))
|
||||
|
||||
# 3. Gemeinsame Interessen
|
||||
a = {"Gaming", "Klettern", "Musik"}
|
||||
b = {"Kochen", "Gaming", "Musik", "Lesen"}
|
||||
print("Gemeinsame Hobbys:", gemeinsame_interessen(a, b))
|
||||
|
||||
# 4. Duplikate entfernen
|
||||
zahlen = [1, 3, 2, 3, 1, 4, 2, 5]
|
||||
print("Bereinigte Zahlenliste:", entferne_duplikate_behalte_reihenfolge(zahlen))
|
||||
142
g09_dictionaries_und_sets/test_aufgabe.py
Normal file
142
g09_dictionaries_und_sets/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import unittest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das aktuelle Verzeichnis im Modulpfad ist
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG09(unittest.TestCase):
|
||||
|
||||
def test_01_woerter_haeufigkeit_grundlagen(self):
|
||||
"""Prüft woerter_haeufigkeit mit einfachen Wörtern."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "woerter_haeufigkeit"),
|
||||
"Fehler: Funktion 'woerter_haeufigkeit' fehlt in aufgabe.py!"
|
||||
)
|
||||
text = "Apfel Banane Apfel Birne Banane Apfel"
|
||||
ergebnis = aufgabe.woerter_haeufigkeit(text)
|
||||
erwartet = {"apfel": 3, "banane": 2, "birne": 1}
|
||||
self.assertIsInstance(ergebnis, dict, "Fehler: Rückgabewert muss ein Dictionary (dict) sein!")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler bei woerter_haeufigkeit: Erwartet {erwartet}, aber erhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
def test_02_woerter_haeufigkeit_satzzeichen_und_grossklein(self):
|
||||
"""Prüft woerter_haeufigkeit bei Groß-/Kleinschreibung und Satzzeichen."""
|
||||
text = "Hallo, hallo! HALLO... ist da wer? Ja, wer da ist."
|
||||
ergebnis = aufgabe.woerter_haeufigkeit(text)
|
||||
erwartet = {"hallo": 3, "ist": 2, "da": 2, "wer": 2, "ja": 1}
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler: Satzzeichen oder Groß-/Kleinschreibung nicht korrekt behandelt!\nErwartet: {erwartet}\nErhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
def test_03_woerter_haeufigkeit_leerer_text(self):
|
||||
"""Prüft woerter_haeufigkeit bei leerem String."""
|
||||
ergebnis = aufgabe.woerter_haeufigkeit("")
|
||||
self.assertEqual(ergebnis, {}, "Fehler: Ein leerer Text sollte ein leeres Dictionary {} liefern.")
|
||||
|
||||
def test_04_telefonbuch_suche_gefunden(self):
|
||||
"""Prüft telefonbuch_suche, wenn der Name existiert."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "telefonbuch_suche"),
|
||||
"Fehler: Funktion 'telefonbuch_suche' fehlt in aufgabe.py!"
|
||||
)
|
||||
buch = {
|
||||
"Anna": "0171-123456",
|
||||
"Ben": "0160-987654",
|
||||
"Clara": "0151-555666"
|
||||
}
|
||||
self.assertEqual(
|
||||
aufgabe.telefonbuch_suche(buch, "Anna"),
|
||||
"0171-123456",
|
||||
"Fehler: Telefonnummer für 'Anna' wurde nicht korrekt zurückgegeben."
|
||||
)
|
||||
self.assertEqual(
|
||||
aufgabe.telefonbuch_suche(buch, "Clara"),
|
||||
"0151-555666",
|
||||
"Fehler: Telefonnummer für 'Clara' wurde nicht korrekt zurückgegeben."
|
||||
)
|
||||
|
||||
def test_05_telefonbuch_suche_nicht_gefunden(self):
|
||||
"""Prüft telefonbuch_suche mit .get() Fallback bei unbekanntem Namen."""
|
||||
buch = {"Anna": "0171-123456"}
|
||||
ergebnis = aufgabe.telefonbuch_suche(buch, "Daniel")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
"Nicht gefunden",
|
||||
f"Fehler: Unbekannter Name muss 'Nicht gefunden' liefern, ergab aber: {ergebnis}"
|
||||
)
|
||||
# Auch bei leerem Buch
|
||||
self.assertEqual(
|
||||
aufgabe.telefonbuch_suche({}, "Niemand"),
|
||||
"Nicht gefunden",
|
||||
"Fehler: Suche in leerem Telefonbuch muss 'Nicht gefunden' liefern."
|
||||
)
|
||||
|
||||
def test_06_gemeinsame_interessen(self):
|
||||
"""Prüft die Mengenoperation Schnittmenge (intersection / &)."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "gemeinsame_interessen"),
|
||||
"Fehler: Funktion 'gemeinsame_interessen' fehlt in aufgabe.py!"
|
||||
)
|
||||
a = {"Gaming", "Klettern", "Musik"}
|
||||
b = {"Kochen", "Gaming", "Musik", "Lesen"}
|
||||
ergebnis = aufgabe.gemeinsame_interessen(a, b)
|
||||
erwartet = {"Gaming", "Musik"}
|
||||
self.assertIsInstance(ergebnis, set, "Fehler: Rückgabewert muss ein Set (Menge) sein!")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler bei gemeinsame_interessen: Erwartet {erwartet}, erhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
def test_07_gemeinsame_interessen_disjunkt(self):
|
||||
"""Prüft gemeinsame_interessen ohne Überschneidung."""
|
||||
a = {"Tennis", "Schwimmen"}
|
||||
b = {"Schach", "Malen"}
|
||||
ergebnis = aufgabe.gemeinsame_interessen(a, b)
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
set(),
|
||||
"Fehler: Bei disjunkten Mengen muss ein leeres Set() zurückgegeben werden."
|
||||
)
|
||||
|
||||
def test_08_entferne_duplikate_behalte_reihenfolge(self):
|
||||
"""Prüft, ob Duplikate entfernt und die ursprüngliche Reihenfolge erhalten wird."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "entferne_duplikate_behalte_reihenfolge"),
|
||||
"Fehler: Funktion 'entferne_duplikate_behalte_reihenfolge' fehlt in aufgabe.py!"
|
||||
)
|
||||
eingabe = [1, 3, 2, 3, 1, 4, 2, 5]
|
||||
ergebnis = aufgabe.entferne_duplikate_behalte_reihenfolge(eingabe)
|
||||
erwartet = [1, 3, 2, 4, 5]
|
||||
self.assertIsInstance(ergebnis, list, "Fehler: Rückgabewert muss eine Liste sein!")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler: Reihenfolge oder Duplikat-Filterung weicht ab!\nErwartet: {erwartet}\nErhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
def test_09_entferne_duplikate_strings_und_randfaelle(self):
|
||||
"""Prüft Duplikatentfernung mit Strings und leerer Liste."""
|
||||
eingabe = ["Apfel", "Banane", "Apfel", "Birne", "Banane", "Orange"]
|
||||
ergebnis = aufgabe.entferne_duplikate_behalte_reihenfolge(eingabe)
|
||||
erwartet = ["Apfel", "Banane", "Birne", "Orange"]
|
||||
self.assertEqual(ergebnis, erwartet)
|
||||
|
||||
# Leere Liste
|
||||
self.assertEqual(aufgabe.entferne_duplikate_behalte_reihenfolge([]), [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
142
g10_comprehensions_datum_algorithmen/README.md
Normal file
142
g10_comprehensions_datum_algorithmen/README.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# Kapitel G10: Comprehensions, Datum & Algorithmen 🚀📅
|
||||
|
||||
Schulabgleich: **Thema 13.0 (Algorithmen & Datumsverarbeitung) & 15.1 (Comprehensions)**
|
||||
|
||||
Herzlich willkommen zum krönenden Abschluss des Grundlagen-Lehrpfads! In diesem Kapitel lernst du drei essenzielle Werkzeuge kennen, die dich von einer Programmieranfängerin zu einer echten Python-Entwicklerin machen:
|
||||
1. **List & Dict Comprehensions** (Eleganter, kompakter Code in einer Zeile)
|
||||
2. **Datum & Uhrzeit** mit dem `datetime`-Modul (Rechnen mit Zeitspannen & Kalendern)
|
||||
3. **Praktische Algorithmen** (Suchen, Filtern, Sortieren mit `key=` und Min/Max-Findung)
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 1. List Comprehensions: Das Schnellschienen-Fließband
|
||||
|
||||
Bisher hast du neue Listen oft mit einer leeren Liste und einer `for`-Schleife befüllt:
|
||||
|
||||
```python
|
||||
# 🐢 Der traditionelle Weg (4 Zeilen):
|
||||
quadrate = []
|
||||
for x in range(1, 6):
|
||||
if x % 2 == 0:
|
||||
quadrate.append(x ** 2)
|
||||
```
|
||||
|
||||
Mit einer **List Comprehension** schreibst du das in **einer einzigen, glasklaren Zeile**:
|
||||
|
||||
```python
|
||||
# 🚀 Der Pythonic Weg mit List Comprehension:
|
||||
quadrate = [x ** 2 for x in range(1, 6) if x % 2 == 0]
|
||||
# Ergebnis: [4, 16]
|
||||
```
|
||||
|
||||
### Die Anatomie einer List Comprehension:
|
||||
```
|
||||
[ WAS_REIN_SOLL for VARIABLE in QUELLE if BEDINGUNG ]
|
||||
(Ausdruck / Map) (x) (Liste) (Filter)
|
||||
```
|
||||
|
||||
### Auch für Dictionaries: Dict Comprehensions
|
||||
Genauso kannst du blitzschnell Dictionaries erzeugen:
|
||||
```python
|
||||
woerter = ["Apfel", "Banane", "Erdbeere"]
|
||||
wort_laengen = {w: len(w) for w in woerter}
|
||||
# Ergebnis: {'Apfel': 5, 'Banane': 6, 'Erdbeere': 8}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📅 2. Datum & Uhrzeit mit dem `datetime`-Modul
|
||||
|
||||
In der echten Softwareentwicklung (z.B. bei Buchungs-Systemen, Online-Shops oder Kalendern) musst du ständig mit Zeitangaben rechnen. Python bringt dafür das mächtige Modul `datetime` mit.
|
||||
|
||||
```python
|
||||
from datetime import datetime, date, timedelta
|
||||
|
||||
# 1. Aktuelles Datum & Uhrzeit:
|
||||
heute = date.today() # z.B. 2026-08-29
|
||||
jetzt = datetime.now() # z.B. 2026-08-29 14:30:00
|
||||
|
||||
# 2. Rechnen mit Zeitspannen (timedelta):
|
||||
in_einer_woche = heute + timedelta(days=7)
|
||||
gestern = heute - timedelta(days=1)
|
||||
|
||||
# 3. Differenz zwischen zwei Daten berechnen:
|
||||
silvester = date(2026, 12, 31)
|
||||
tage_rest = (silvester - heute).days
|
||||
print(f"Noch {tage_rest} Tage bis Silvester!")
|
||||
```
|
||||
|
||||
### Formatieren (`strftime`) & Einlesen (`strptime`)
|
||||
|
||||
- **`strftime` (String Format Time):** Wandelt ein Datumsobjekt in einen formatierten Text um.
|
||||
- **`strptime` (String Parse Time):** Liest einen Text ein und baut daraus ein Datumsobjekt.
|
||||
|
||||
```python
|
||||
# Objekt -> Formatierter String:
|
||||
datum = date(2026, 8, 29)
|
||||
deutsch = datum.strftime("%d.%m.%Y") # "29.08.2026"
|
||||
|
||||
# String -> Datumsobjekt:
|
||||
text = "2026-12-24"
|
||||
weihnachten = datetime.strptime(text, "%Y-%m-%d").date()
|
||||
```
|
||||
|
||||
| Platzhalter | Bedeutung | Beispiel |
|
||||
| :--- | :--- | :--- |
|
||||
| `%d` | Tag des Monats (01 - 31) | `29` |
|
||||
| `%m` | Monat als Zahl (01 - 12) | `08` |
|
||||
| `%Y` | Jahr vierstellig | `2026` |
|
||||
| `%H` | Stunde (00 - 23) | `14` |
|
||||
| `%M` | Minute (00 - 59) | `35` |
|
||||
| `%S` | Sekunde (00 - 59) | `09` |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 3. Grundlegende Algorithmen: Suchen, Finden & Sortieren
|
||||
|
||||
### A. Lineare Suche
|
||||
Wenn du ein Element in einer Liste suchst, durchläufst du die Liste von vorne nach hinten:
|
||||
|
||||
```python
|
||||
def finde_person(personen, gesuchter_name):
|
||||
for person in personen:
|
||||
if person["name"] == gesuchter_name:
|
||||
return person
|
||||
return None
|
||||
```
|
||||
|
||||
### B. Maximum & Minimum mit Schlüssel (`key=`)
|
||||
Wie findet man die älteste Person oder das teuerste Produkt?
|
||||
|
||||
```python
|
||||
gruppe = [
|
||||
{"name": "Anna", "alter": 25},
|
||||
{"name": "Ben", "alter": 32},
|
||||
{"name": "Clara", "alter": 19}
|
||||
]
|
||||
|
||||
# Die Person mit dem höchsten Alter:
|
||||
aelteste = max(gruppe, key=lambda person: person["alter"])
|
||||
print("Älteste Person:", aelteste["name"]) # "Ben"
|
||||
|
||||
# Sortieren nach Alter aufsteigend:
|
||||
sortiert = sorted(gruppe, key=lambda p: p["alter"])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Deine Aufgaben in `aufgabe.py`
|
||||
|
||||
Öffne die Datei `g10_comprehensions_datum_algorithmen/aufgabe.py` und löse die 5 TODOs:
|
||||
|
||||
1. **TODO 1 (`quadratzahlen_gerade`):** Berechne die Quadrate aller geraden Zahlen mit einer List Comprehension.
|
||||
2. **TODO 2 (`filtriere_lange_woerter`):** Filtere Wörter heraus, deren Länge `>= min_laenge` ist.
|
||||
3. **TODO 3 (`tage_bis_datum`):** Berechne die Anzahl der Tage von heute bis zu einem Zieldatum (`YYYY-MM-DD`).
|
||||
4. **TODO 4 (`formatiere_deutsches_datum`):** Formatiere ein Datumsobjekt in das Format `DD.MM.YYYY`.
|
||||
5. **TODO 5 (`finde_aelteste_person`):** Finde in einer Liste von Personen-Dictionaries den Namen der ältesten Person.
|
||||
|
||||
### Testen:
|
||||
```bash
|
||||
python3 test_aufgabe.py
|
||||
```
|
||||
Sobald alle Tests `OK` sind, hast du den gesamten Grundlagen-Pfad erfolgreich abgeschlossen! 🏆🎉
|
||||
148
g10_comprehensions_datum_algorithmen/aufgabe.py
Normal file
148
g10_comprehensions_datum_algorithmen/aufgabe.py
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
"""
|
||||
Kapitel G10: Comprehensions, Datum & Algorithmen – Aufgabenblatt
|
||||
================================================================
|
||||
Schulabgleich: Thema 13.0 & 15.1
|
||||
|
||||
In diesem Kapitel meisterst du drei fortgeschrittene Kernkompetenzen:
|
||||
1. List & Dict Comprehensions (kompakter, eleganter Python-Code)
|
||||
2. Datum & Uhrzeit mit dem 'datetime'-Modul (Rechnen mit Tagen & Zeitspannen)
|
||||
3. Grundlegende Algorithmen (Filtern, Suchen und Min/Max-Ermittlung)
|
||||
|
||||
Bearbeite die Aufgaben von TODO 1 bis TODO 5.
|
||||
Überprüfe deine Lösung im Terminal mit:
|
||||
python3 test_aufgabe.py
|
||||
"""
|
||||
|
||||
from datetime import datetime, date, timedelta
|
||||
from typing import List, Dict, Union
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 1: Quadratzahlen gerader Zahlen (List Comprehension)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'quadratzahlen_gerade(zahlen: list[int]) -> list[int]'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Verwende eine elegante List Comprehension: [ausdruck for x in ... if ...]
|
||||
# 2. Filtere alle geraden Zahlen (x % 2 == 0) heraus.
|
||||
# 3. Berechne für jede gefilterte Zahl das Quadrat (x ** 2).
|
||||
# 4. Gib die neue Liste zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# eingabe = [1, 2, 3, 4, 5, 6]
|
||||
# Ergebnis: [4, 16, 36] (denn 2²=4, 4²=16, 6²=36)
|
||||
# ==============================================================================
|
||||
|
||||
def quadratzahlen_gerade(zahlen: List[int]) -> List[int]:
|
||||
"""Gibt die Quadrate aller geraden Zahlen als List Comprehension zurück."""
|
||||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 2: Wörter nach Mindestlänge filtern
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'filtriere_lange_woerter(woerter: list[str], min_laenge: int) -> list[str]'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Verwende vorzugsweise eine List Comprehension.
|
||||
# 2. Behalte nur Wörter, deren Zeichenlänge größer oder gleich 'min_laenge' ist (len(w) >= min_laenge).
|
||||
# 3. Gib die gefilterte Liste zurück.
|
||||
#
|
||||
# Beispiel:
|
||||
# liste = ["Python", "ist", "eine", "tolle", "Sprache"]
|
||||
# filtriere_lange_woerter(liste, 5) -> ["Python", "tolle", "Sprache"]
|
||||
# ==============================================================================
|
||||
|
||||
def filtriere_lange_woerter(woerter: List[str], min_laenge: int) -> List[str]:
|
||||
"""Filtert alle Wörter heraus, die mindestens 'min_laenge' Zeichen lang sind."""
|
||||
# Schreibe hier deinen Code für TODO 2:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 3: Tage bis Zieldatum berechnen (datetime & timedelta)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'tage_bis_datum(ziel_datum_str: str) -> int'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Der Parameter 'ziel_datum_str' ist ein Datum im Format "YYYY-MM-DD" (z.B. "2026-12-24").
|
||||
# 2. Lies den Text mit 'datetime.strptime(ziel_datum_str, "%Y-%m-%d").date()' ein.
|
||||
# 3. Ermittle das heutige Datum mit 'date.today()'.
|
||||
# 4. Berechne die Differenz: (ziel_datum - heute).days.
|
||||
# 5. Gib die Anzahl der verbleibenden Tage als Ganzzahl (int) zurück.
|
||||
# (Positiv = in der Zukunft, Negativ = in der Vergangenheit, 0 = heute).
|
||||
# ==============================================================================
|
||||
|
||||
def tage_bis_datum(ziel_datum_str: str) -> int:
|
||||
"""Berechnet die Anzahl der Tage von heute bis zum angegebenen Zieldatum (YYYY-MM-DD)."""
|
||||
# Schreibe hier deinen Code für TODO 3:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 4: Datum im deutschen Format darstellen (.strftime)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'formatiere_deutsches_datum(datum_obj: Union[date, datetime]) -> str'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. Die Funktion erhält ein 'date'- oder 'datetime'-Objekt.
|
||||
# 2. Formatiere das Datum mit '.strftime()' im deutschen Standard-Format "DD.MM.YYYY" (z.B. "24.12.2026").
|
||||
# Tipp: %d = Tag (zweistellig), %m = Monat (zweistellig), %Y = Jahr (vierstellig).
|
||||
# 3. Gib den formatierten String zurück.
|
||||
# ==============================================================================
|
||||
|
||||
def formatiere_deutsches_datum(datum_obj: Union[date, datetime]) -> str:
|
||||
"""Formatiert ein date- oder datetime-Objekt in das deutsche Format DD.MM.YYYY."""
|
||||
# Schreibe hier deinen Code für TODO 4:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# TODO 5: Älteste Person finden (Algorithmus: Maximum / Key-Suche)
|
||||
# ------------------------------------------------------------------------------
|
||||
# Schreibe eine Funktion 'finde_aelteste_person(personen: list[dict]) -> str'.
|
||||
#
|
||||
# Anforderungen:
|
||||
# 1. 'personen' ist eine Liste von Dictionaries, z.B.:
|
||||
# [{"name": "Anna", "alter": 25}, {"name": "Ben", "alter": 32}, {"name": "Clara", "alter": 19}]
|
||||
# 2. Wenn die Liste leer ist, gib einen leeren String "" zurück.
|
||||
# 3. Finde die Person mit dem höchsten 'alter' (z.B. mit Schleife oder max(..., key=...)).
|
||||
# 4. Gib den 'name' dieser ältesten Person zurück (im Beispiel: "Ben").
|
||||
# ==============================================================================
|
||||
|
||||
def finde_aelteste_person(personen: List[Dict[str, Union[str, int]]]) -> str:
|
||||
"""Findet in einer Liste von Personen-Dicts die älteste Person und gibt deren Namen zurück."""
|
||||
# Schreibe hier deinen Code für TODO 5:
|
||||
pass
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Hauptprogramm zum Ausprobieren:
|
||||
# (Du kannst diese Datei direkt mit 'python3 aufgabe.py' ausführen)
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
print("--- 🚀 Testlauf: Comprehensions, Datum & Algorithmen ---")
|
||||
|
||||
# Test TODO 1
|
||||
zahlen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
print("Quadrate gerader Zahlen:", quadratzahlen_gerade(zahlen))
|
||||
|
||||
# Test TODO 2
|
||||
woerter = ["Code", "Python", "KI", "Entwicklung", "Funktion", "Loop"]
|
||||
print("Wörter >= 6 Zeichen:", filtriere_lange_woerter(woerter, 6))
|
||||
|
||||
# Test TODO 3 & 4
|
||||
heute = date.today()
|
||||
print("Heutiges deutsches Datum:", formatiere_deutsches_datum(heute))
|
||||
|
||||
silvester = f"{heute.year}-12-31"
|
||||
print(f"Tage bis zum Jahresende ({silvester}):", tage_bis_datum(silvester))
|
||||
|
||||
# Test TODO 5
|
||||
gruppe = [
|
||||
{"name": "Lisa", "alter": 21},
|
||||
{"name": "Markus", "alter": 29},
|
||||
{"name": "Sarah", "alter": 24}
|
||||
]
|
||||
print("Älteste Person in der Gruppe:", finde_aelteste_person(gruppe))
|
||||
255
g10_comprehensions_datum_algorithmen/index.html
Normal file
255
g10_comprehensions_datum_algorithmen/index.html
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel G10: Comprehensions, Datum & Algorithmen</title>
|
||||
<link rel="stylesheet" href="../assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<nav class="nav-links">
|
||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||
<span>›</span>
|
||||
<a href="../g09_dictionaries_und_sets/index.html">← Kapitel G09</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel G10</span>
|
||||
<span>›</span>
|
||||
<a href="../00_fehlersuche_und_grundlagen/index.html">Lehrpfad 2: OOP →</a>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel G10 • Schulabgleich 13.0 & 15.1</div>
|
||||
<h1>Comprehensions, Datum & Algorithmen 🚀📅</h1>
|
||||
<p>Lerne, wie du elegante Einzeiler schreibst, mit Zeitspannen rechnest und grundlegende Such- und Filter-Algorithmen meisterst.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- 1. List Comprehensions: Das Schnellschienen-Fließband -->
|
||||
<section class="card">
|
||||
<h2>1. List Comprehensions: Das Schnellschienen-Fließband</h2>
|
||||
|
||||
<p>
|
||||
In Python musst du nicht jedes Mal eine leere Liste erstellen und eine 4-zeilige <code>for</code>-Schleife mit <code>.append()</code> schreiben.
|
||||
Mit <strong>List Comprehensions</strong> erstellst und filterst du Listen in einer einzigen, eleganten Zeile!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏭 Die Fließband- & Filtersieb-Analogie:</div>
|
||||
<p>Stell dir ein automatisiertes Fließband in einer Manufaktur vor:</p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li>Die Rohstoffe (Elemente aus der Ausgangsliste) laufen über das Band (<code>for x in liste</code>).</li>
|
||||
<li>Ein Sensor sortiert unpassende Teile sofort aus (<code>if x % 2 == 0</code>).</li>
|
||||
<li>Am Ende wird das Teil direkt veredelt oder berechnet (<code>x ** 2</code>) und fällt fertig verpackt in die neue Liste!</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<div class="code-dots">
|
||||
<span class="code-dot dot-red"></span>
|
||||
<span class="code-dot dot-yellow"></span>
|
||||
<span class="code-dot dot-green"></span>
|
||||
</div>
|
||||
<span>Vergleich: Traditionelle Schleife vs. List Comprehension</span>
|
||||
</div>
|
||||
<pre><span class="cm"># 🐢 Vorher: Traditionelle for-Schleife (4 Zeilen)</span>
|
||||
<span class="var">gerade_quadrate</span> = []
|
||||
<span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="num">7</span>):
|
||||
<span class="kw">if</span> <span class="var">x</span> % <span class="num">2</span> == <span class="num">0</span>:
|
||||
<span class="var">gerade_quadrate</span>.<span class="fn">append</span>(<span class="var">x</span> ** <span class="num">2</span>)
|
||||
|
||||
<span class="cm"># 🚀 Nachher: Elegante List Comprehension (1 Zeile!)</span>
|
||||
<span class="var">gerade_quadrate</span> = [<span class="var">x</span> ** <span class="num">2</span> <span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> <span class="fn">range</span>(<span class="num">1</span>, <span class="num">7</span>) <span class="kw">if</span> <span class="var">x</span> % <span class="num">2</span> == <span class="num">0</span>]
|
||||
<span class="fn">print</span>(<span class="var">gerade_quadrate</span>) <span class="cm"># [4, 16, 36]</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>Dict Comprehensions: Dictionaries on the fly</h3>
|
||||
<div class="code-container">
|
||||
<div class="code-header"><span>Dict Comprehension Syntax</span></div>
|
||||
<pre><span class="var">woerter</span> = [<span class="str">"Python"</span>, <span class="str">"Code"</span>, <span class="str">"Entwicklung"</span>]
|
||||
<span class="var">laengen</span> = {<span class="var">w</span>: <span class="fn">len</span>(<span class="var">w</span>) <span class="kw">for</span> <span class="var">w</span> <span class="kw">in</span> <span class="var">woerter</span>}
|
||||
<span class="fn">print</span>(<span class="var">laengen</span>) <span class="cm"># {'Python': 6, 'Code': 4, 'Entwicklung': 11}</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 2. Datum & Zeit mit datetime -->
|
||||
<section class="card">
|
||||
<h2>2. Datum, Uhrzeit & Zeitspannen (Das <code>datetime</code>-Modul)</h2>
|
||||
|
||||
<p>
|
||||
Egal ob Ticket-Buchung, Geburtstags-Erinnerung oder Spielstand-Speicherung: Zeitberechnungen gehören zum Alltag jeder Programmiererin.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🗓️ Die Kalender- & Stoppuhr-Analogie:</div>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li><code>date</code> & <code>datetime</code> sind wie dein Kalender: Ein festes Datum wie der 24.12.2026.</li>
|
||||
<li><code>timedelta</code> ist wie eine Zeitspanne (z.B. "+ 14 Tage" oder "- 3 Stunden").</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Python: Rechnen mit datetime & timedelta</span>
|
||||
</div>
|
||||
<pre><span class="kw">from</span> <span class="var">datetime</span> <span class="kw">import</span> <span class="var">datetime</span>, <span class="var">date</span>, <span class="var">timedelta</span>
|
||||
|
||||
<span class="cm"># 1. Heute ermitteln:</span>
|
||||
<span class="var">heute</span> = <span class="var">date</span>.<span class="fn">today</span>()
|
||||
|
||||
<span class="cm"># 2. Text in Datum parsen (.strptime):</span>
|
||||
<span class="var">urlaub</span> = <span class="var">datetime</span>.<span class="fn">strptime</span>(<span class="str">"2026-07-15"</span>, <span class="str">"%Y-%m-%d"</span>).<span class="fn">date</span>()
|
||||
|
||||
<span class="cm"># 3. Differenz in Tagen berechnen:</span>
|
||||
<span class="var">tage_bis_urlaub</span> = (<span class="var">urlaub</span> - <span class="var">heute</span>).<span class="attr">days</span>
|
||||
<span class="fn">print</span>(<span class="str">f"Noch {tage_bis_urlaub} Tage bis zum Urlaub!"</span>)
|
||||
|
||||
<span class="cm"># 4. Deutsches Datumsformat ausgeben (.strftime):</span>
|
||||
<span class="fn">print</span>(<span class="var">urlaub</span>.<span class="fn">strftime</span>(<span class="str">"%d.%m.%Y"</span>)) <span class="cm"># Ausgabe: "15.07.2026"</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>Wichtige Formatierungs-Kürzel</h3>
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 15px 0;">
|
||||
<thead>
|
||||
<tr style="background: var(--primary-light); text-align: left;">
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Kürzel</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Bedeutung</th>
|
||||
<th style="padding: 10px; border: 1px solid var(--border-color);">Beispiel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>%d</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Tag im Monat mit führender Null (01..31)</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>05</code> oder <code>29</code></td>
|
||||
</tr>
|
||||
<tr style="background: #fafafa;">
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>%m</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Monat mit führender Null (01..12)</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>08</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>%Y</code></td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);">Vierstelliges Jahr</td>
|
||||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>2026</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- 3. Grundlegende Algorithmen -->
|
||||
<section class="card">
|
||||
<h2>3. Grundlegende Algorithmen: Min/Max, Suchen & Sortieren</h2>
|
||||
|
||||
<p>
|
||||
Ein <strong>Algorithmus</strong> ist eine präzise Handlungsanweisung zur Lösung eines Problems.
|
||||
Hier lernst du die wichtigsten Muster kennen:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Maximum suchen mit key=</span>
|
||||
</div>
|
||||
<pre><span class="var">personen</span> = [
|
||||
{<span class="str">"name"</span>: <span class="str">"Anna"</span>, <span class="str">"alter"</span>: <span class="num">25</span>},
|
||||
{<span class="str">"name"</span>: <span class="str">"Ben"</span>, <span class="str">"alter"</span>: <span class="num">32</span>},
|
||||
{<span class="str">"name"</span>: <span class="str">"Clara"</span>, <span class="str">"alter"</span>: <span class="num">19</span>}
|
||||
]
|
||||
|
||||
<span class="cm"># Die älteste Person mit max() und Lambda-Schlüssel finden:</span>
|
||||
<span class="var">aelteste</span> = <span class="fn">max</span>(<span class="var">personen</span>, <span class="var">key</span>=<span class="kw">lambda</span> <span class="var">p</span>: <span class="var">p</span>[<span class="str">"alter"</span>])
|
||||
<span class="fn">print</span>(<span class="str">f"Älteste Person: {aelteste['name']} ({aelteste['alter']} Jahre)"</span>)
|
||||
<span class="cm"># Ausgabe: Älteste Person: Ben (32 Jahre)</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. Aufgaben & Checkliste -->
|
||||
<section class="card">
|
||||
<h2>4. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>g10_comprehensions_datum_algorithmen/aufgabe.py</code> und bearbeite die folgenden 5 Aufgaben:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t1">
|
||||
<label for="t1" class="task-label">
|
||||
<strong>TODO 1 (<code>quadratzahlen_gerade</code>):</strong> Erzeuge mit einer List Comprehension eine Liste mit den Quadraten aller geraden Zahlen.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2 (<code>filtriere_lange_woerter</code>):</strong> Filtere alle Wörter heraus, deren Zeichenlänge mindestens <code>min_laenge</code> beträgt.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3">
|
||||
<label for="t3" class="task-label">
|
||||
<strong>TODO 3 (<code>tage_bis_datum</code>):</strong> Parse ein Datums-String (<code>YYYY-MM-DD</code>) und berechne die Differenz in Tagen zu heute.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4">
|
||||
<label for="t4" class="task-label">
|
||||
<strong>TODO 4 (<code>formatiere_deutsches_datum</code>):</strong> Formatiere ein <code>date</code>- oder <code>datetime</code>-Objekt mit <code>.strftime()</code> im Format <code>DD.MM.YYYY</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5">
|
||||
<label for="t5" class="task-label">
|
||||
<strong>TODO 5 (<code>finde_aelteste_person</code>):</strong> Suche in einer Liste von Personen-Dictionaries die Person mit dem größten Alter und gib ihren Namen zurück (oder <code>""</code> bei leerer Liste).
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 1 & 2 (List Comprehensions)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="cm"># TODO 1:</span>
|
||||
<span class="kw">return</span> [<span class="var">x</span> ** <span class="num">2</span> <span class="kw">for</span> <span class="var">x</span> <span class="kw">in</span> <span class="var">zahlen</span> <span class="kw">if</span> <span class="var">x</span> % <span class="num">2</span> == <span class="num">0</span>]
|
||||
|
||||
<span class="cm"># TODO 2:</span>
|
||||
<span class="kw">return</span> [<span class="var">w</span> <span class="kw">for</span> <span class="var">w</span> <span class="kw">in</span> <span class="var">woerter</span> <span class="kw">if</span> <span class="fn">len</span>(<span class="var">w</span>) >= <span class="var">min_laenge</span>]</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔍 Tipp zu TODO 3 (Datum einlesen & subtrahieren)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="var">ziel</span> = <span class="var">datetime</span>.<span class="fn">strptime</span>(<span class="var">ziel_datum_str</span>, <span class="str">"%Y-%m-%d"</span>).<span class="fn">date</span>()
|
||||
<span class="var">heute</span> = <span class="var">date</span>.<span class="fn">today</span>()
|
||||
<span class="kw">return</span> (<span class="var">ziel</span> - <span class="var">heute</span>).<span class="attr">days</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- 5. Testen & Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. 🧪 Lösung überprüfen & Kursabschluss</h2>
|
||||
<p>Führe den Test im Terminal aus:</p>
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../g09_dictionaries_und_sets/index.html" class="btn btn-secondary">← Zurück zu Kapitel G09</a>
|
||||
<a href="../00_fehlersuche_und_grundlagen/index.html" class="btn">Weiter zu Lehrpfad 2: OOP & Klassen →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
72
g10_comprehensions_datum_algorithmen/musterloesung.py
Normal file
72
g10_comprehensions_datum_algorithmen/musterloesung.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""
|
||||
Kapitel G10: Comprehensions, Datum & Algorithmen – Musterlösung
|
||||
================================================================
|
||||
Schulabgleich: Thema 13.0 & 15.1
|
||||
|
||||
Hier findest du die vollständige Musterlösung zu allen Aufgaben.
|
||||
"""
|
||||
|
||||
from datetime import datetime, date, timedelta
|
||||
from typing import List, Dict, Union
|
||||
|
||||
|
||||
# TODO 1: Quadratzahlen gerader Zahlen (List Comprehension)
|
||||
def quadratzahlen_gerade(zahlen: List[int]) -> List[int]:
|
||||
"""Gibt die Quadrate aller geraden Zahlen als List Comprehension zurück."""
|
||||
return [x ** 2 for x in zahlen if x % 2 == 0]
|
||||
|
||||
|
||||
# TODO 2: Wörter nach Mindestlänge filtern
|
||||
def filtriere_lange_woerter(woerter: List[str], min_laenge: int) -> List[str]:
|
||||
"""Filtert alle Wörter heraus, die mindestens 'min_laenge' Zeichen lang sind."""
|
||||
return [w for w in woerter if len(w) >= min_laenge]
|
||||
|
||||
|
||||
# TODO 3: Tage bis Zieldatum berechnen (datetime & timedelta)
|
||||
def tage_bis_datum(ziel_datum_str: str) -> int:
|
||||
"""Berechnet die Anzahl der Tage von heute bis zum angegebenen Zieldatum (YYYY-MM-DD)."""
|
||||
ziel_datum = datetime.strptime(ziel_datum_str, "%Y-%m-%d").date()
|
||||
heute = date.today()
|
||||
return (ziel_datum - heute).days
|
||||
|
||||
|
||||
# TODO 4: Datum im deutschen Format darstellen (.strftime)
|
||||
def formatiere_deutsches_datum(datum_obj: Union[date, datetime]) -> str:
|
||||
"""Formatiert ein date- oder datetime-Objekt in das deutsche Format DD.MM.YYYY."""
|
||||
return datum_obj.strftime("%d.%m.%Y")
|
||||
|
||||
|
||||
# TODO 5: Älteste Person finden (Algorithmus: Maximum / Key-Suche)
|
||||
def finde_aelteste_person(personen: List[Dict[str, Union[str, int]]]) -> str:
|
||||
"""Findet in einer Liste von Personen-Dicts die älteste Person und gibt deren Namen zurück."""
|
||||
if not personen:
|
||||
return ""
|
||||
aelteste = max(personen, key=lambda p: p["alter"])
|
||||
return str(aelteste["name"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("--- 🚀 Musterlösung G10: Comprehensions, Datum & Algorithmen ---")
|
||||
|
||||
# 1. Quadratzahlen
|
||||
test_zahlen = [1, 2, 3, 4, 5, 6]
|
||||
print("Gerade Quadrate:", quadratzahlen_gerade(test_zahlen))
|
||||
|
||||
# 2. Wörter filtern
|
||||
woerter_liste = ["Python", "ist", "klasse", "und", "schnell"]
|
||||
print("Wörter >= 6:", filtriere_lange_woerter(woerter_liste, 6))
|
||||
|
||||
# 3. Tage bis Zieldatum
|
||||
morgen = (date.today() + timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
print(f"Tage bis morgen ({morgen}):", tage_bis_datum(morgen))
|
||||
|
||||
# 4. Deutsches Datum
|
||||
print("Heute im deutschen Format:", formatiere_deutsches_datum(date.today()))
|
||||
|
||||
# 5. Älteste Person
|
||||
leute = [
|
||||
{"name": "Anna", "alter": 25},
|
||||
{"name": "Ben", "alter": 35},
|
||||
{"name": "Clara", "alter": 28}
|
||||
]
|
||||
print("Älteste Person:", finde_aelteste_person(leute))
|
||||
143
g10_comprehensions_datum_algorithmen/test_aufgabe.py
Normal file
143
g10_comprehensions_datum_algorithmen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import unittest
|
||||
import sys
|
||||
from datetime import datetime, date, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
# Sicherstellen, dass das aktuelle Verzeichnis im Modulpfad ist
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
try:
|
||||
import aufgabe
|
||||
except ImportError as e:
|
||||
raise ImportError(f"Konnte 'aufgabe.py' nicht importieren: {e}")
|
||||
|
||||
|
||||
class TestKapitelG10(unittest.TestCase):
|
||||
|
||||
def test_01_quadratzahlen_gerade(self):
|
||||
"""Prüft, ob quadratzahlen_gerade Quadrate der geraden Zahlen liefert."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "quadratzahlen_gerade"),
|
||||
"Fehler: Funktion 'quadratzahlen_gerade' fehlt in aufgabe.py!"
|
||||
)
|
||||
eingabe = [1, 2, 3, 4, 5, 6]
|
||||
ergebnis = aufgabe.quadratzahlen_gerade(eingabe)
|
||||
erwartet = [4, 16, 36]
|
||||
self.assertIsInstance(ergebnis, list, "Fehler: Rückgabewert muss eine Liste sein!")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler: Erwartet {erwartet}, aber erhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
# Nur ungerade Zahlen
|
||||
self.assertEqual(aufgabe.quadratzahlen_gerade([1, 3, 5, 7]), [])
|
||||
# Leere Liste
|
||||
self.assertEqual(aufgabe.quadratzahlen_gerade([]), [])
|
||||
|
||||
def test_02_filtriere_lange_woerter(self):
|
||||
"""Prüft, ob filtriere_lange_woerter Wörter nach Mindestlänge filtert."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "filtriere_lange_woerter"),
|
||||
"Fehler: Funktion 'filtriere_lange_woerter' fehlt in aufgabe.py!"
|
||||
)
|
||||
woerter = ["Python", "ist", "eine", "tolle", "Sprache"]
|
||||
ergebnis = aufgabe.filtriere_lange_woerter(woerter, 5)
|
||||
erwartet = ["Python", "tolle", "Sprache"]
|
||||
self.assertIsInstance(ergebnis, list, "Fehler: Rückgabewert muss eine Liste sein!")
|
||||
self.assertEqual(
|
||||
ergebnis,
|
||||
erwartet,
|
||||
f"Fehler: Erwartet {erwartet}, aber erhalten: {ergebnis}"
|
||||
)
|
||||
|
||||
# Hohe Mindestlänge (kein Treffer)
|
||||
self.assertEqual(aufgabe.filtriere_lange_woerter(woerter, 20), [])
|
||||
# Mindestlänge 0 (alle Wörter)
|
||||
self.assertEqual(aufgabe.filtriere_lange_woerter(woerter, 0), woerter)
|
||||
|
||||
def test_03_tage_bis_datum(self):
|
||||
"""Prüft die Datumsberechnung mit strptime und timedelta."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "tage_bis_datum"),
|
||||
"Fehler: Funktion 'tage_bis_datum' fehlt in aufgabe.py!"
|
||||
)
|
||||
heute = date.today()
|
||||
|
||||
# 1. Heute
|
||||
heute_str = heute.strftime("%Y-%m-%d")
|
||||
self.assertEqual(aufgabe.tage_bis_datum(heute_str), 0, "Fehler: Tage bis heute muss 0 sein!")
|
||||
|
||||
# 2. In 14 Tagen
|
||||
zukunft = heute + timedelta(days=14)
|
||||
zukunft_str = zukunft.strftime("%Y-%m-%d")
|
||||
self.assertEqual(
|
||||
aufgabe.tage_bis_datum(zukunft_str),
|
||||
14,
|
||||
f"Fehler: Tage bis {zukunft_str} sollte 14 sein!"
|
||||
)
|
||||
|
||||
# 3. Vor 5 Tagen
|
||||
vergangenheit = heute - timedelta(days=5)
|
||||
vergangenheit_str = vergangenheit.strftime("%Y-%m-%d")
|
||||
self.assertEqual(
|
||||
aufgabe.tage_bis_datum(vergangenheit_str),
|
||||
-5,
|
||||
f"Fehler: Tage bis {vergangenheit_str} sollte -5 sein!"
|
||||
)
|
||||
|
||||
def test_04_formatiere_deutsches_datum(self):
|
||||
"""Prüft die Formatierung mit .strftime in DD.MM.YYYY."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "formatiere_deutsches_datum"),
|
||||
"Fehler: Funktion 'formatiere_deutsches_datum' fehlt in aufgabe.py!"
|
||||
)
|
||||
# Test mit date Objekt
|
||||
d1 = date(2026, 12, 24)
|
||||
self.assertEqual(
|
||||
aufgabe.formatiere_deutsches_datum(d1),
|
||||
"24.12.2026",
|
||||
"Fehler: date(2026, 12, 24) sollte als '24.12.2026' formatiert werden."
|
||||
)
|
||||
|
||||
# Test mit datetime Objekt und einstelligen Ziffern (Prüfung führender Nullen)
|
||||
dt = datetime(2025, 3, 4, 15, 30)
|
||||
self.assertEqual(
|
||||
aufgabe.formatiere_deutsches_datum(dt),
|
||||
"04.03.2025",
|
||||
"Fehler: Führende Nullen beachten! datetime(2025, 3, 4) -> '04.03.2025'."
|
||||
)
|
||||
|
||||
def test_05_finde_aelteste_person(self):
|
||||
"""Prüft die Algorithmus-Suche nach der ältesten Person."""
|
||||
self.assertTrue(
|
||||
hasattr(aufgabe, "finde_aelteste_person"),
|
||||
"Fehler: Funktion 'finde_aelteste_person' fehlt in aufgabe.py!"
|
||||
)
|
||||
personen = [
|
||||
{"name": "Anna", "alter": 25},
|
||||
{"name": "Ben", "alter": 32},
|
||||
{"name": "Clara", "alter": 19}
|
||||
]
|
||||
self.assertEqual(
|
||||
aufgabe.finde_aelteste_person(personen),
|
||||
"Ben",
|
||||
"Fehler: 'Ben' (32) ist die älteste Person."
|
||||
)
|
||||
|
||||
# Einzelne Person
|
||||
self.assertEqual(
|
||||
aufgabe.finde_aelteste_person([{"name": "Opa Wilhelm", "alter": 88}]),
|
||||
"Opa Wilhelm"
|
||||
)
|
||||
|
||||
# Leere Liste
|
||||
self.assertEqual(
|
||||
aufgabe.finde_aelteste_person([]),
|
||||
"",
|
||||
"Fehler: Bei leerer Personenliste soll ein leerer String '' zurückgegeben werden."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
279
index.html
279
index.html
|
|
@ -3,16 +3,51 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Python OOP Lernportal: Klassen & Objekte</title>
|
||||
<title>Python Lernportal: Grundlagen, OOP & Software-Entwicklung</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
<style>
|
||||
.track-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.track-1-badge { background: #dbeafe; color: #1e40af; }
|
||||
.track-2-badge { background: #e0e7ff; color: #4338ca; }
|
||||
.track-3-badge { background: #dcfce7; color: #166534; }
|
||||
.section-header {
|
||||
margin: 40px 0 15px 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.section-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.45rem;
|
||||
color: var(--text-main);
|
||||
}
|
||||
.section-desc {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.95rem;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-container">
|
||||
<div class="header-badge">🐍 Python Nachhilfe & Selbstlern-Kurs</div>
|
||||
<h1>Objektorientierte Programmierung (OOP)</h1>
|
||||
<p>Lerne Schritt für Schritt, wie du eigene Klassen baust, Methoden nutzt und professionell mit Git & Unit Tests arbeitest.</p>
|
||||
<div class="header-badge">🐍 Python Nachhilfe- & Selbstlern-Portal</div>
|
||||
<h1>Vom Einsteiger zum Software-Entwickler</h1>
|
||||
<p>3 strukturierte Lehrpfade: Prozedurale Grundlagen • Objektorientierung • Professionelle Werkzeuge (Git, TDD, Tkinter)</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
@ -20,25 +55,160 @@
|
|||
|
||||
<!-- Willkommen Card -->
|
||||
<section class="card">
|
||||
<h2>👋 Willkommen zu deiner Übungsreihe!</h2>
|
||||
<h2>👋 Willkommen zu deiner interaktiven Python-Lernreise!</h2>
|
||||
<p>
|
||||
Dieser Kurs begleitet dich durch die gesamte Objektorientierte Programmierung in Python – exakt abgestimmt auf dein Schulskriptum, aber mit viel mehr Erklärungen, Analogien, Visualisierungen und automatischen Tests!
|
||||
Dieses Portal begleitet dich Schritt für Schritt von den ersten Schritten in Python bis hin zu vollständigen Desktop-Apps mit grafischer Oberfläche. Alle Aufgaben sind mit verständlichen Erklärungen, Alltags-Analogien, visuellen Beispielen und <strong>automatischen Tests</strong> für sofortiges Feedback ausgestattet.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏗️ Die Grundidee von OOP in einem Satz:</div>
|
||||
Eine <strong>Klasse</strong> ist wie ein Bauplan (oder eine Plätzchen-Ausstechform). Ein <strong>Objekt</strong> ist das fertige Haus (oder das gebackene Plätzchen), das nach diesem Bauplan entstanden ist!
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px; margin: 20px 0;">
|
||||
<div style="background: #f8fafc; border-left: 4px solid #3b82f6; padding: 15px; border-radius: var(--radius-sm);">
|
||||
<span class="track-badge track-1-badge">Lehrpfad 1</span>
|
||||
<h4 style="margin: 0 0 6px 0; color: #1e3a8a;">🌱 Grundlagen der Programmierung</h4>
|
||||
<p style="font-size: 0.88rem; color: var(--text-muted); margin: 0;">Für Einsteiger oder zur Wiederholung: Rechnen, Variablen, Bedingungen, Schleifen, Funktionen, Listen, Dictionaries & Strings (G01–G10).</p>
|
||||
</div>
|
||||
<div style="background: #f8fafc; border-left: 4px solid #6366f1; padding: 15px; border-radius: var(--radius-sm);">
|
||||
<span class="track-badge track-2-badge">Lehrpfad 2</span>
|
||||
<h4 style="margin: 0 0 6px 0; color: #312e81;">🏗️ Einstieg in OOP & Tools</h4>
|
||||
<p style="font-size: 0.88rem; color: var(--text-muted); margin: 0;">Klassen, Baupläne, <code>__init__</code>, Methoden, UML-Diagramme, VS Code Umstieg, Git-Versionskontrolle & Tamagotchi-Projekt (00–06).</p>
|
||||
</div>
|
||||
<div style="background: #f8fafc; border-left: 4px solid #22c55e; padding: 15px; border-radius: var(--radius-sm);">
|
||||
<span class="track-badge track-3-badge">Lehrpfad 3</span>
|
||||
<h4 style="margin: 0 0 6px 0; color: #14532d;">🚀 Fortgeschrittenes OOP & GUIs</h4>
|
||||
<p style="font-size: 0.88rem; color: var(--text-muted); margin: 0;">Speicher-Referenzen, Dunder-Methoden, eigene Unit Tests (TDD), Vererbung, Polymorphie, Exceptions, JSON-Persistenz & Tkinter (07–14).</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">📚 Schulabgleich & Lehrplan:</div>
|
||||
Alle Kapitel sind 1:1 mit den Themen deines Informatik-Unterrichts (Type Hints, UML, Assoziationen, Referenzen, Vererbung, Tkinter) abgestimmt. Ausführlicher Plan in <a href="LEHRPLAN.md" style="color: var(--primary); font-weight: bold;">LEHRPLAN.md</a>.
|
||||
Alle Kapitel sind 1:1 mit dem offiziellen Skriptum des Informatik-Unterrichts abgestimmt. Detaillierter Leitfaden in <a href="LEHRPLAN.md" style="color: var(--primary); font-weight: bold;">LEHRPLAN.md</a>.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PHASE 1: GRUNDLAGEN & WERKZEUGE -->
|
||||
<!-- LEHRPFAD 1: GRUNDLAGEN -->
|
||||
<section>
|
||||
<h2 style="margin: 30px 0 10px 0; color: var(--text-main); font-size: 1.4rem;">🌱 Phase 1: Grundlagen OOP & Entwickler-Werkzeuge</h2>
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<h2>🛣️ Lehrpfad 1: Grundlagen der Programmierung (Prozedural)</h2>
|
||||
<div class="section-desc">Die unverzichtbare Basis: Datentypen, Kontrollstrukturen, Funktionen und Datenstrukturen.</div>
|
||||
</div>
|
||||
<span class="track-badge track-1-badge">10 Kapitel • G01 bis G10</span>
|
||||
</div>
|
||||
|
||||
<div class="roadmap-grid">
|
||||
|
||||
<!-- G01 -->
|
||||
<a href="g01_erste_schritte_taschenrechner/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G01</span>
|
||||
<div class="roadmap-title">🧮 Python als Taschenrechner</div>
|
||||
<div class="roadmap-desc">Zahlen (<code>int</code>, <code>float</code>), Grundrechenarten, Ganzzahldivision <code>//</code>, Modulo <code>%</code>, Potenzen <code>**</code> & <code>print()</code>.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G01 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G02 -->
|
||||
<a href="g02_variablen_und_datentypen/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G02</span>
|
||||
<div class="roadmap-title">📦 Variablen & Datentypen</div>
|
||||
<div class="roadmap-desc">Speicherboxen, die 4 Basisdatentypen (<code>int</code>, <code>float</code>, <code>str</code>, <code>bool</code>), Type Casting & Type Hints.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G02 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G03 -->
|
||||
<a href="g03_ein_und_ausgabe/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G03</span>
|
||||
<div class="roadmap-title">💬 Interaktive Ein- & Ausgabe</div>
|
||||
<div class="roadmap-desc">Benutzereingaben mit <code>input()</code>, Textumwandlung und moderne formatierte <code>f-Strings</code> (z.B. <code>{preis:.2f} €</code>).</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G03 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G04 -->
|
||||
<a href="g04_verzweigungen_und_bedingungen/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G04</span>
|
||||
<div class="roadmap-title">🚦 Bedingungen & Verzweigungen</div>
|
||||
<div class="roadmap-desc">Entscheidungen treffen mit <code>if</code>, <code>elif</code>, <code>else</code>, Vergleichs- und Logikoperatoren (<code>and</code>, <code>or</code>, <code>not</code>).</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G04 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G05 -->
|
||||
<a href="g05_schleifen_und_wiederholungen/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G05</span>
|
||||
<div class="roadmap-title">🎡 Schleifen & Wiederholungen</div>
|
||||
<div class="roadmap-desc">Zählschleifen mit <code>for in range(...)</code>, Bedingungsschleifen mit <code>while</code>, <code>break</code> & <code>continue</code>.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G05 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G06 -->
|
||||
<a href="g06_funktionen_und_module/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G06</span>
|
||||
<div class="roadmap-title">🪄 Eigene Funktionen & Module</div>
|
||||
<div class="roadmap-desc">Wiederverwendbarer Code mit <code>def</code>, <code>return</code>, Parametern, Scope und Modulen (<code>math</code>, <code>random</code>).</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G06 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G07 -->
|
||||
<a href="g07_listen_und_sequenzen/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G07</span>
|
||||
<div class="roadmap-title">📋 Listen & Sequenzen</div>
|
||||
<div class="roadmap-desc">Elemente speichern, Indexzugriff, Slicing (<code>[1:4]</code>), Listen-Methoden (<code>append</code>, <code>pop</code>) & <code>sum/len/min/max</code>.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G07 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G08 -->
|
||||
<a href="g08_textverarbeitung_und_strings/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G08</span>
|
||||
<div class="roadmap-title">🔤 Textverarbeitung & Strings</div>
|
||||
<div class="roadmap-desc">String-Methoden wie <code>.strip()</code>, <code>.replace()</code>, <code>.split()</code>, <code>.join()</code> und Palindrom-Analyse.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G08 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G09 -->
|
||||
<a href="g09_dictionaries_und_sets/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G09</span>
|
||||
<div class="roadmap-title">🗃️ Dictionaries & Sets</div>
|
||||
<div class="roadmap-desc">Schlüssel-Wert-Paare (<code>{key: val}</code>), sicheres <code>.get()</code>, Telefonbuch-Suche & Mengen (<code>set</code>) ohne Duplikate.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G09 öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- G10 -->
|
||||
<a href="g10_comprehensions_datum_algorithmen/index.html" class="roadmap-card" style="border-left: 4px solid #3b82f6;">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #dbeafe; color: #1e40af;">Grundlagen G10</span>
|
||||
<div class="roadmap-title">🚀 Comprehensions & Algorithmen</div>
|
||||
<div class="roadmap-desc">List Comprehensions (<code>[x for x in ...]</code>), <code>datetime</code> für Kalenderberechnungen & Min/Max-Suche.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel G10 öffnen →</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- LEHRPFAD 2: EINSTIEG IN OOP & WERKZEUGE -->
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<h2>🛣️ Lehrpfad 2: Einstieg in OOP & Entwickler-Werkzeuge</h2>
|
||||
<div class="section-desc">Der Übergang zur Objektorientierung: Baupläne, Methoden, UML, VS Code & Git.</div>
|
||||
</div>
|
||||
<span class="track-badge track-2-badge">Kapitel 00 bis 06</span>
|
||||
</div>
|
||||
|
||||
<div class="roadmap-grid">
|
||||
|
||||
<!-- Kapitel 0 -->
|
||||
|
|
@ -46,9 +216,9 @@
|
|||
<div>
|
||||
<span class="roadmap-number" style="background: var(--purple-light); color: var(--purple);">Warm-up 00</span>
|
||||
<div class="roadmap-title">🔍 Fehlersuche & Bugs</div>
|
||||
<div class="roadmap-desc">Tracebacks richtig lesen, Einrückungsfehler (IndentationError), Typfehler und Detektiv-Aufgabe.</div>
|
||||
<div class="roadmap-desc">Tracebacks von unten lesen, Einrückungen (IndentationError), Typfehler und Detektiv-Aufgabe.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Vorkapitel öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 1 -->
|
||||
|
|
@ -95,10 +265,10 @@
|
|||
<a href="04b_umstieg_vscode/index.html" class="roadmap-card" style="border-left: 4px solid var(--secondary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #e0f2fe; color: #0284c7;">Exkurs 04b</span>
|
||||
<div class="roadmap-title">🚀 Umstieg & Installation VS Code</div>
|
||||
<div class="roadmap-title">🚀 Installation & Setup VS Code</div>
|
||||
<div class="roadmap-desc">Installationsanleitung (Win/Mac/Linux), Plugins (Error Lens, Python), Shortcuts & Terminal.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">VS Code Guide öffnen →</div>
|
||||
<div class="roadmap-footer">VS Code Guide →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 4c (Git) -->
|
||||
|
|
@ -106,9 +276,9 @@
|
|||
<div>
|
||||
<span class="roadmap-number" style="background: var(--success-light); color: var(--success);">Exkurs 04c</span>
|
||||
<div class="roadmap-title">🌿 Git & Versionskontrolle</div>
|
||||
<div class="roadmap-desc">Die Programmier-Zeitmaschine: Spielstände (Commits) sichern, Diffs in VS Code, Terminal-Befehle & Push.</div>
|
||||
<div class="roadmap-desc">Die Programmier-Zeitmaschine: Spielstände (Commits) sichern, Diffs in VS Code, Terminal & Push.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Git Guide öffnen →</div>
|
||||
<div class="roadmap-footer">Git Guide →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 5 -->
|
||||
|
|
@ -134,9 +304,16 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PHASE 2: FORTGESCHRITTENES OOP -->
|
||||
<!-- LEHRPFAD 3: FORTGESCHRITTENES OOP -->
|
||||
<section>
|
||||
<h2 style="margin: 35px 0 10px 0; color: var(--text-main); font-size: 1.4rem;">🧠 Phase 2: Fortgeschrittenes OOP, Testing & Persistenz</h2>
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<h2>🛣️ Lehrpfad 3: Fortgeschrittenes OOP, Testing & Desktop-GUIs</h2>
|
||||
<div class="section-desc">Professionelle Softwaretechnik: Speicherverwaltung, Vererbung, TDD-Tests, Persistenz und GUIs.</div>
|
||||
</div>
|
||||
<span class="track-badge track-3-badge">Kapitel 07 bis 14</span>
|
||||
</div>
|
||||
|
||||
<div class="roadmap-grid">
|
||||
|
||||
<!-- Kapitel 7 -->
|
||||
|
|
@ -144,91 +321,81 @@
|
|||
<div>
|
||||
<span class="roadmap-number" style="background: var(--success-light); color: var(--success);">Kapitel 07</span>
|
||||
<div class="roadmap-title">🌳 Referenzen & Stammbäume</div>
|
||||
<div class="roadmap-desc">Speicherbereiche im RAM, Aliasing (<code>b = a</code>), <code>is</code> vs. <code>==</code> und Familienstammbaum-Klassen.</div>
|
||||
<div class="roadmap-desc">Speicherbereiche im RAM, Aliasing (<code>b = a</code>), <code>is</code> vs. <code>==</code> und Familienstammbäume.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 07 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 8 -->
|
||||
<a href="08_operator_overloading_dunder/index.html" class="roadmap-card" style="border-left: 4px solid var(--secondary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #e0f2fe; color: #0284c7;">Kapitel 08 • Neu</span>
|
||||
<span class="roadmap-number" style="background: #e0f2fe; color: #0284c7;">Kapitel 08</span>
|
||||
<div class="roadmap-title">➕ Operator Overloading & Dunder</div>
|
||||
<div class="roadmap-desc">Eigene Klassen rechen- und vergleichbar machen mit <code>__add__</code>, <code>__mul__</code>, <code>__eq__</code>, <code>__lt__</code> für 2D-Vektoren & Wegstrecken.</div>
|
||||
<div class="roadmap-desc">Eigene Klassen rechenbar machen mit <code>__add__</code>, <code>__mul__</code>, <code>__eq__</code> für 2D-Vektoren & Wegstrecken.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 08 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 9 -->
|
||||
<a href="09_eigene_unit_tests_schreiben/index.html" class="roadmap-card" style="border-left: 4px solid var(--primary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 09 • Neu</span>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 09</span>
|
||||
<div class="roadmap-title">🧪 Eigene Unit Tests & TDD</div>
|
||||
<div class="roadmap-desc">Schreibe eigene Testsuiten mit <code>unittest</code>, <code>self.assertEqual()</code>, <code>assertRaises()</code> und lerne Test-Driven Development.</div>
|
||||
<div class="roadmap-desc">Schreibe eigene Testsuiten mit <code>unittest</code>, <code>self.assertEqual()</code>, <code>assertRaises()</code> und lerne TDD.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 09 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 10 -->
|
||||
<a href="10_vererbung_und_super/index.html" class="roadmap-card" style="border-left: 4px solid var(--primary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 10 • Neu</span>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 10</span>
|
||||
<div class="roadmap-title">🧬 Vererbung & super()</div>
|
||||
<div class="roadmap-desc">DRY-Prinzip, Basis- & Kindklassen, <code>super().__init__()</code>, Methoden erweitern & Fahrzeugflotten-Hierarchie.</div>
|
||||
<div class="roadmap-desc">DRY-Prinzip, Basis- & Kindklassen, <code>super().__init__()</code>, Methoden erweitern & Fahrzeugflotten.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 10 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 11 -->
|
||||
<a href="11_polymorphie_und_interfaces/index.html" class="roadmap-card" style="border-left: 4px solid var(--secondary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: #e0f2fe; color: #0284c7;">Kapitel 11 • Neu</span>
|
||||
<span class="roadmap-number" style="background: #e0f2fe; color: #0284c7;">Kapitel 11</span>
|
||||
<div class="roadmap-title">🎭 Polymorphie & Interfaces</div>
|
||||
<div class="roadmap-desc">Vielgestaltigkeit, Duck Typing, abstrakte Basisklassen (<code>ABC</code>), Geometrie-Engine & Zeichenflächen-Manager.</div>
|
||||
<div class="roadmap-desc">Vielgestaltigkeit, Duck Typing, abstrakte Basisklassen (<code>ABC</code>), Geometrie-Engine & Zeichenflächen.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 11 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 12 -->
|
||||
<a href="12_exceptions_und_fehlerbehandlung/index.html" class="roadmap-card" style="border-left: 4px solid var(--danger);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: var(--danger-light); color: var(--danger);">Kapitel 12 • Neu</span>
|
||||
<span class="roadmap-number" style="background: var(--danger-light); color: var(--danger);">Kapitel 12</span>
|
||||
<div class="roadmap-title">🛡️ Exceptions & Fehlerbehandlung</div>
|
||||
<div class="roadmap-desc">Robuste Fehlerkontrolle mit <code>try-except-else-finally</code>, <code>raise</code> und eigene Exception-Klassen im Bankkonto-Simulator.</div>
|
||||
<div class="roadmap-desc">Robuste Fehlerkontrolle mit <code>try-except-else-finally</code>, <code>raise</code> und eigene Fehlerklassen im Banking.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 12 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 13 -->
|
||||
<a href="13_persistenz_json_und_csv/index.html" class="roadmap-card" style="border-left: 4px solid var(--primary);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 13 • Neu</span>
|
||||
<span class="roadmap-number" style="background: var(--primary-light); color: var(--primary);">Kapitel 13</span>
|
||||
<div class="roadmap-title">💾 Datei-Persistenz: JSON & CSV</div>
|
||||
<div class="roadmap-desc">Dauerhaftes Speichern & Laden: Savegames mit <code>to_dict()</code>/<code>from_dict()</code>, <code>json.dump</code> und CSV-Tabellen-Export.</div>
|
||||
<div class="roadmap-desc">Dauerhaftes Speichern & Laden: Savegames mit <code>to_dict()</code>/<code>from_dict()</code>, <code>json.dump</code> und CSV-Export.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 13 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 14 -->
|
||||
<a href="14_gui_mit_tkinter/index.html" class="roadmap-card" style="border-left: 4px solid var(--purple);">
|
||||
<div>
|
||||
<span class="roadmap-number" style="background: var(--purple-light); color: var(--purple);">Kapitel 14 • Neu</span>
|
||||
<span class="roadmap-number" style="background: var(--purple-light); color: var(--purple);">Kapitel 14</span>
|
||||
<div class="roadmap-title">🖥️ Desktop-GUIs mit Tkinter</div>
|
||||
<div class="roadmap-desc">Fenster, Buttons, Labels, Grid-Layout, Event-Loop und MVC-Architektur im interaktiven Zähler & Rechner.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel 14 öffnen →</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Vorschau Kapitel 8-11 & 15-16 -->
|
||||
<div class="roadmap-card" style="opacity: 0.85;">
|
||||
<div>
|
||||
<span class="roadmap-number">Weitere Kapitel • Geplant</span>
|
||||
<div class="roadmap-title">🧬 Vererbung, Polymorphie & Master-Projekt</div>
|
||||
<div class="roadmap-desc">Operator Overloading (08), Unit Testing (09), Vererbung (10), Polymorphie (11), Parameter (15) und Master-Projekt (16).</div>
|
||||
</div>
|
||||
<div class="roadmap-footer" style="color: var(--text-muted);">Ausführlicher Plan in LEHRPLAN.md</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -246,9 +413,9 @@
|
|||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal (Beispiel für Kapitel 01)</span>
|
||||
<span>Terminal (Beispiel für Grundlagen G01)</span>
|
||||
</div>
|
||||
<pre><code>cd 01_einstieg_klassen
|
||||
<pre><code>cd g01_erste_schritte_taschenrechner
|
||||
python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
|
||||
|
|
@ -293,7 +460,7 @@ object has no attribute 'gang'</code></pre>
|
|||
<div class="box-title">💡 Die 3 goldenen Regeln beim Arbeiten mit Tests:</div>
|
||||
<ol style="margin-left: 20px; margin-top: 6px;">
|
||||
<li style="margin-bottom: 6px;"><strong>Immer <code>return</code> statt nur <code>print()</code>:</strong> Tests prüfen das, was eine Funktion mit <code>return</code> zurückliefert. Ein <code>print()</code> zeigt es zwar auf dem Bildschirm an, reicht dem Test aber nicht!</li>
|
||||
<li style="margin-bottom: 6px;"><strong>Exakte Namen beachten:</strong> Wenn die Aufgabe <code>def mutter_setzen(self):</code> verlangt, darf die Methode nicht <code>def MutterSetzen</code> heißen (Python unterscheidet Groß- und Kleinschreibung).</li>
|
||||
<li style="margin-bottom: 6px;"><strong>Exakte Namen beachten:</strong> Wenn die Aufgabe <code>def addieren(a, b):</code> verlangt, darf die Funktion nicht <code>def Addieren</code> heißen (Python unterscheidet Groß- und Kleinschreibung).</li>
|
||||
<li style="margin-bottom: 6px;"><strong>Fehlermeldungen von unten nach oben lesen:</strong> Ganz unten steht immer genau, was nicht gepasst hat!</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
|
@ -322,7 +489,7 @@ object has no attribute 'gang'</code></pre>
|
|||
<details>
|
||||
<summary>❌ Wie wechsle ich im Terminal zwischen den Ordnern hin und her?</summary>
|
||||
<div class="details-content">
|
||||
<p><strong>In einen Unterordner hinein:</strong> <code>cd 01_einstieg_klassen</code></p>
|
||||
<p><strong>In einen Unterordner hinein:</strong> <code>cd g01_erste_schritte_taschenrechner</code></p>
|
||||
<p><strong>Einen Ordner nach oben zurück:</strong> <code>cd ..</code></p>
|
||||
<p><strong>Inhalt des aktuellen Ordners auflisten:</strong> <code>ls</code> (oder <code>dir</code> auf Windows)</p>
|
||||
</div>
|
||||
|
|
|
|||
10
test_all.py
10
test_all.py
|
|
@ -11,6 +11,16 @@ import unittest
|
|||
from pathlib import Path
|
||||
|
||||
KAPITEL = [
|
||||
("Grundlagen 01: Python als Taschenrechner", "g01_erste_schritte_taschenrechner"),
|
||||
("Grundlagen 02: Variablen & Datentypen", "g02_variablen_und_datentypen"),
|
||||
("Grundlagen 03: Interaktive Ein- & Ausgabe", "g03_ein_und_ausgabe"),
|
||||
("Grundlagen 04: Verzweigungen & Bedingungen", "g04_verzweigungen_und_bedingungen"),
|
||||
("Grundlagen 05: Schleifen & Wiederholungen", "g05_schleifen_und_wiederholungen"),
|
||||
("Grundlagen 06: Eigene Funktionen & Module", "g06_funktionen_und_module"),
|
||||
("Grundlagen 07: Listen & Sequenzen", "g07_listen_und_sequenzen"),
|
||||
("Grundlagen 08: Textverarbeitung & Strings", "g08_textverarbeitung_und_strings"),
|
||||
("Grundlagen 09: Dictionaries & Sets", "g09_dictionaries_und_sets"),
|
||||
("Grundlagen 10: Comprehensions & Algorithmen", "g10_comprehensions_datum_algorithmen"),
|
||||
("Kapitel 00: Python-Fehlersuche (Warm-up)", "00_fehlersuche_und_grundlagen"),
|
||||
("Kapitel 01: Einstieg in Klassen", "01_einstieg_klassen"),
|
||||
("Kapitel 02: Konstruktor & self", "02_init_und_self"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue