diff --git a/01_einstieg_klassen/README.md b/01_einstieg_klassen/README.md
index 4a6cfea..8178b43 100644
--- a/01_einstieg_klassen/README.md
+++ b/01_einstieg_klassen/README.md
@@ -1,10 +1,10 @@
-# Kapitel 01: Die erste Klasse – Was sind Klassen & Objekte?
+# Kapitel 01: Die erste Klasse – Was sind Klassen & Objekte? 🐶🐱
-Herzlich willkommen in der Welt der objektorientierten Programmierung (kurz: **OOP**)! 🐶🐱
+Herzlich willkommen in der Welt der objektorientierten Programmierung (kurz: **OOP**)!
Bisher hast du in Python mit Variablen, Listen, Dictionaries und Funktionen gearbeitet. Das hat super funktioniert! Doch wenn Programme größer werden, wird es schnell unübersichtlich.
-Hier kommen **Klassen** ins Spiel.
+Mit **Klassen** lernst du jetzt, wie du deine eigenen, maßgeschneiderten Datentypen erstellst.
---
@@ -43,7 +43,7 @@ Eine einfache Klasse definierst du mit dem Schlüsselwort `class`:
```python
class Auto:
- pass # 'pass' bedeutet: "Hier passiert erst mal nichts"
+ pass # 'pass' bedeutet: "Hier passiert erst mal nichts weiter"
```
Aus dieser Klasse kannst du nun ein Objekt erzeugen (**Instanziierung**):
@@ -71,16 +71,31 @@ dein_auto.ps = 180
---
-## 🎯 Deine Aufgabe
+## ⚠️ Häufige Stolperfallen für Einsteiger
-Öffne jetzt die Datei `aufgabe.py` und bearbeite die Aufgaben:
-1. Erstelle die Klasse `Haustier`.
-2. Erzeuge zwei Haustier-Objekte `bello` und `mimi` mit Eigenschaften.
-3. Schreibe zwei kleine Hilfsfunktionen, die mit deinen Haustier-Objekten arbeiten.
+1. **Groß- und Kleinschreibung:**
+ - Klassen werden per Konvention in **CamelCase** mit großem Anfangsbuchstaben geschrieben: `class Haustier:`, `class BankKonto:`.
+ - Variablen und Funktionen schreibt man klein mit Unterstrichen: `mein_haustier = Haustier()`.
+2. **Klammern beim Erstellen nicht vergessen:**
+ - `bello = Haustier()` erzeugt ein neues Objekt.
+ - `bello = Haustier` (ohne Klammern) würde die Klasse selbst speichern, kein neues Objekt erzeugen!
+3. **`return` in Funktionen nicht vergessen:**
+ - Wenn deine Funktion ein neu gebautes Haustier erzeugen soll, muss am Ende `return tier` stehen, sonst gibt die Funktion `None` zurück.
+
+---
+
+## 🎯 Deine Aufgaben in `aufgabe.py`
+
+Öffne jetzt die Datei `aufgabe.py` und bearbeite die nummerierten TODOs:
+1. **TODO 1:** Definiere die leere Klasse `Haustier`.
+2. **TODO 2:** Schreibe die Funktion `erstelle_bello()`.
+3. **TODO 3:** Schreibe die Funktion `erstelle_mimi()`.
+4. **TODO 4:** Schreibe die Funktion `steckbrief_text(haustier)`.
+5. **TODO 5:** Schreibe die Funktion `aelteres_tier(tier1, tier2)`.
### Testen:
Führe deine Tests aus mit:
```bash
python3 test_aufgabe.py
```
-Sobald alle Tests bestanden sind, kannst du mit Kapitel 02 weitermachen!
+Sobald alle Tests mit `OK` durchlaufen, bist du bereit für Kapitel 02!
diff --git a/01_einstieg_klassen/aufgabe.py b/01_einstieg_klassen/aufgabe.py
index 5b8d88f..e9b7dd9 100644
--- a/01_einstieg_klassen/aufgabe.py
+++ b/01_einstieg_klassen/aufgabe.py
@@ -3,13 +3,16 @@ Kapitel 01: Die erste Klasse – Aufgabenblatt
============================================
Bearbeite die Aufgaben Schritt für Schritt von TODO 1 bis TODO 5.
-Wenn du fertig bist, überprüfe deine Lösung mit:
+Wenn du fertig bist, überprüfe deine Lösung im Terminal mit:
python3 test_aufgabe.py
"""
# ==============================================================================
# TODO 1: Definiere eine leere Klasse namens "Haustier".
-# Tipp: Verwende das Schlüsselwort 'class' und vorerst 'pass' im Klassenrumpf.
+#
+# Erklärung:
+# Eine Klasse ist ein Bauplan.
+# Schreibe 'class Haustier:' und rück in der nächsten Zeile 'pass' ein.
# ==============================================================================
# Schreibe hier deinen Code für TODO 1:
@@ -18,13 +21,14 @@ Wenn du fertig bist, überprüfe deine Lösung mit:
# ==============================================================================
# TODO 2: Erstelle eine Funktion namens "erstelle_bello()".
-# Diese Funktion soll:
-# 1. Ein neues Haustier-Objekt erzeugen.
-# 2. Dem Objekt folgende Attribute zuweisen:
-# - name: "Bello"
-# - tierart: "Hund"
-# - alter: 3
-# 3. Das fertige Objekt zurückgeben (return).
+#
+# Schritt-für-Schritt-Anleitung:
+# 1. Erstelle ein neues Haustier-Objekt: z.B. hund = Haustier()
+# 2. Setze die drei Attribute mit dem Punkt-Operator:
+# hund.name = "Bello"
+# hund.tierart = "Hund"
+# hund.alter = 3
+# 3. Gib das erstellte Objekt mit 'return hund' zurück!
# ==============================================================================
def erstelle_bello():
@@ -34,13 +38,12 @@ def erstelle_bello():
# ==============================================================================
# TODO 3: Erstelle eine Funktion namens "erstelle_mimi()".
-# Diese Funktion soll:
-# 1. Ein neues Haustier-Objekt erzeugen.
-# 2. Dem Objekt folgende Attribute zuweisen:
-# - name: "Mimi"
-# - tierart: "Katze"
-# - alter: 5
-# 3. Das fertige Objekt zurückgeben (return).
+#
+# Ähnlich wie bei Bello:
+# - name = "Mimi"
+# - tierart = "Katze"
+# - alter = 5
+# Vergiss nicht das 'return'!
# ==============================================================================
def erstelle_mimi():
@@ -50,13 +53,15 @@ def erstelle_mimi():
# ==============================================================================
# TODO 4: Schreibe eine Funktion "steckbrief_text(haustier)".
+#
# Die Funktion bekommt ein Haustier-Objekt als Parameter übergeben.
# Sie soll einen formatierten Text im folgenden Format zurückgeben:
# "{name} ist ein(e) {tierart} und ist {alter} Jahre alt."
#
+# Tipp: Nutze einen f-String: f"{haustier.name} ist ein(e) {haustier.tierart} ..."
+#
# Beispiel:
-# Wenn bello übergeben wird, soll zurückgegeben werden:
-# "Bello ist ein(e) Hund und ist 3 Jahre alt."
+# Wenn bello übergeben wird: "Bello ist ein(e) Hund und ist 3 Jahre alt."
# ==============================================================================
def steckbrief_text(haustier):
@@ -66,9 +71,16 @@ def steckbrief_text(haustier):
# ==============================================================================
# TODO 5: Schreibe eine Funktion "aelteres_tier(tier1, tier2)".
+#
# Die Funktion bekommt zwei Haustier-Objekte übergeben.
# Sie soll dasjenige Haustier-Objekt zurückgeben, dessen 'alter' größer ist.
# Wenn beide Tiere gleich alt sind, soll tier1 zurückgegeben werden.
+#
+# Tipp:
+# if tier2.alter > tier1.alter:
+# return tier2
+# else:
+# return tier1
# ==============================================================================
def aelteres_tier(tier1, tier2):
@@ -89,6 +101,6 @@ if __name__ == "__main__":
print(steckbrief_text(bello))
print(steckbrief_text(mimi))
aelter = aelteres_tier(bello, mimi)
- print(f"Das ältere Tier ist: {aelter.name}")
+ print(f"Das ältere Tier ist: {aelter.name} ({aelter.alter} Jahre)")
else:
- print("Hinweis: Implementiere erst die TODOs, um die Ausgabe zu sehen!")
+ print("💡 Hinweis: Implementiere erst die TODOs, um die Ausgabe zu sehen!")
diff --git a/01_einstieg_klassen/index.html b/01_einstieg_klassen/index.html
new file mode 100644
index 0000000..8426656
--- /dev/null
+++ b/01_einstieg_klassen/index.html
@@ -0,0 +1,192 @@
+
+
+
+
+
+ Kapitel 01: Einstieg in Klassen
+
+
+
+
+
+
+
+
Kapitel 01
+
Die erste Klasse: Bauplan vs. Objekt 🐶
+
Verstehe den Unterschied zwischen einer Klasse und einer Instanz und baue deine ersten Haustier-Objekte.
+
+
+
+
+
+
+
+
1. Die wichtigste Idee: Bauplan vs. Haus
+
+
+ In Python ist alles, was du bisher kennengelernt hast (Zahlen, Strings, Listen, Dictionaries), im Grunde ein Objekt. Doch jetzt lernst du, wie du deine ganz eigenen Datentypen erfindest!
+
+
+
+
🏗️ Die Plätzchenform-Analogie:
+
Stell dir das Backen vor:
+
+
Die Klasse (class) ist die Ausstechform. Sie legt fest: Jedes Plätzchen hat einen Kopf, zwei Arme und zwei Beine. Die Form selbst kann man aber nicht essen.
+
Das Objekt (Instanz) ist das echte Plätzchen, das du aus dem Teig ausstichst. Ein Plätzchen bekommt Schokoglasur, das andere Zuckerstreusel. Beide stammen aus derselben Form, sind aber eigenständig!
+
+
+
+
Warum nicht einfach Dictionaries?
+
Ein Dictionary hat keine feste Struktur – man vertippt sich leicht:
+
+
+
+
+
+
+
+
+ Python (Problem mit Dictionaries)
+
+
tier1 = {"name": "Bello", "tierart": "Hund", "alter": 3}
+tier2 = {"name": "Mimi", "art": "Katze", "alter": 5} # Ups! 'art' statt 'tierart'!
+# Ein Programm würde hier abstürzen, weil tier2["tierart"] nicht existiert!
+
+
+
Mit einer Klasse definierst du eine klare, wiederverwendbare Struktur.
+
+
+
+
+
2. Wie definiert und nutzt man eine Klasse?
+
+
Eine einfache Klasse erstellst du mit dem Schlüsselwort class:
+
+
+
+
+
+
+
+
+ Python
+
+
# 1. Bauplan definieren:
+classAuto:
+ pass# pass bedeutet: Hier steht erst mal kein weiterer Code
+
+# 2. Ein Objekt erzeugen (Instanziierung):
+mein_auto = Auto()
+
+# 3. Eigenschaften (Attribute) mit dem Punkt (.) setzen:
+mein_auto.farbe = "Rot"
+mein_auto.marke = "VW"
+mein_auto.ps = 110
+
+# 4. Werte wieder abfragen:
+print(mein_auto.farbe) # Gibt "Rot" aus
+ In Python schreibt man Klassennamen standardmäßig in CamelCase mit großem Anfangsbuchstaben (z.B. Haustier, BankKonto), während Variablen und Funktionen klein geschrieben werden (z.B. mein_haustier, erstelle_tier()).
+
+
+
+
+
+
3. Deine Aufgaben in aufgabe.py
+
+
Öffne die Datei 01_einstieg_klassen/aufgabe.py und bearbeite die nummerierten TODOs:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
💡 Lösungshinweise (Aufklappen bei Bedarf)
+
+
+ Tipp zu TODO 1 & 2 (Objekt erstellen und befüllen)
+
Führe im Terminal im Ordner 01_einstieg_klassen folgenden Befehl aus:
+
+
+ Terminal
+
+
python3 test_aufgabe.py
+
+
+
+
+
+
+
+
+
diff --git a/02_init_und_self/README.md b/02_init_und_self/README.md
index 6c29963..52082c8 100644
--- a/02_init_und_self/README.md
+++ b/02_init_und_self/README.md
@@ -77,6 +77,20 @@ k2 = Bankkonto("Ben", 50.0)
---
+## ⚠️ Typische Fehler vermeiden
+
+1. **`__init__` mit zwei Unterstrichen schreiben:**
+ - ❌ `def _init_(self):` (wird nicht aufgerufen!)
+ - ✅ `def __init__(self):` (korrekt!)
+2. **`self` bei jeder Methode als ersten Parameter:**
+ - ❌ `def einzahlen(betrag):` -> führt zu `TypeError: einzahlen() takes 1 positional argument but 2 were given`
+ - ✅ `def einzahlen(self, betrag):`
+3. **Zuweisungsrichtung beachten:**
+ - ❌ `inhaber = self.inhaber` (falsch herum!)
+ - ✅ `self.inhaber = inhaber` (speichert den Parameter im Attribut)
+
+---
+
## 🎯 Deine Aufgabe: Das Bankkonto
Öffne `aufgabe.py`. Du programmierst eine Klasse `Bankkonto`:
diff --git a/02_init_und_self/aufgabe.py b/02_init_und_self/aufgabe.py
index 3ad4a4b..3082ba7 100644
--- a/02_init_und_self/aufgabe.py
+++ b/02_init_und_self/aufgabe.py
@@ -10,9 +10,11 @@ class Bankkonto:
# TODO 1: Schreibe die __init__-Methode.
# Parameter: self, inhaber (String), kontostand (Float, Standardwert 0.0)
#
- # Speichere die Parameter als Attribute an 'self':
- # - self.inhaber
- # - self.kontostand
+ # Anleitung:
+ # 1. Definiere: def __init__(self, inhaber, kontostand=0.0):
+ # 2. Speichere die übergebenen Werte an self:
+ # self.inhaber = inhaber
+ # self.kontostand = kontostand
# ==========================================================================
def __init__(self, inhaber, kontostand=0.0):
# Schreibe hier deinen Code für TODO 1:
@@ -20,13 +22,14 @@ class Bankkonto:
# ==========================================================================
# TODO 2: Schreibe die Methode "einzahlen(self, betrag)".
+ #
# Regeln:
# 1. Wenn 'betrag' größer als 0 ist:
- # - Erhöhe 'self.kontostand' um 'betrag'.
+ # - Erhöhe 'self.kontostand' um 'betrag': self.kontostand += betrag
# - Gib True zurück (Einzahlung erfolgreich).
- # 2. Wenn 'betrag' kleiner oder gleich 0 ist:
- # - Verändere den Kontostand nicht.
- # - Gib False zurück (ungültiger Betrag).
+ # 2. Wenn 'betrag' kleiner oder gleich 0 ist (z.B. 0 oder -5):
+ # - Ändere nichts am Kontostand.
+ # - Gib False zurück.
# ==========================================================================
def einzahlen(self, betrag):
# Schreibe hier deinen Code für TODO 2:
@@ -34,13 +37,12 @@ class Bankkonto:
# ==========================================================================
# TODO 3: Schreibe die Methode "auszahlen(self, betrag)".
+ #
# Regeln:
- # 1. Der Betrag muss größer als 0 sein UND es muss genug Geld auf dem Konto
- # sein (self.kontostand >= betrag).
- # - Ziehe 'betrag' von 'self.kontostand' ab.
- # - Gib True zurück (Auszahlung erfolgreich).
- # 2. Andernfalls (nicht genug Geld oder ungültiger Betrag):
- # - Verändere den Kontostand nicht.
+ # 1. Prüfe mit 'if', ob 'betrag > 0' UND 'self.kontostand >= betrag':
+ # - Wenn ja: Ziehe den Betrag ab (self.kontostand -= betrag)
+ # - Gib True zurück.
+ # 2. Wenn nicht (nicht genug Geld da oder ungültiger Betrag):
# - Gib False zurück.
# ==========================================================================
def auszahlen(self, betrag):
@@ -49,10 +51,12 @@ class Bankkonto:
# ==========================================================================
# TODO 4: Schreibe die Methode "info_text(self)".
- # Sie soll einen String im folgenden Format zurückgeben:
+ #
+ # Sie soll einen formatierten String zurückgeben:
# "Konto von {inhaber}: {kontostand:.2f} Euro"
#
# Beispiel: Bei inhaber="Mia" und kontostand=25.5 -> "Konto von Mia: 25.50 Euro"
+ # Tipp: f"Konto von {self.inhaber}: {self.kontostand:.2f} Euro"
# ==========================================================================
def info_text(self):
# Schreibe hier deinen Code für TODO 4:
@@ -61,17 +65,22 @@ class Bankkonto:
# ==============================================================================
# Hauptprogramm zum Ausprobieren:
+# (Direkt ausführen mit 'python3 aufgabe.py')
# ==============================================================================
if __name__ == "__main__":
print("--- Teste dein Bankkonto ---")
konto = Bankkonto("Mia", 20.0)
- print(konto.info_text())
+
+ if hasattr(konto, "inhaber") and konto.inhaber:
+ print(konto.info_text())
- erfolg = konto.einzahlen(15.5)
- print(f"15.50€ eingezahlt? {erfolg} -> Neuer Stand: {konto.kontostand}€")
+ erfolg = konto.einzahlen(15.5)
+ print(f"15.50€ eingezahlt? {erfolg} -> Neuer Stand: {konto.kontostand:.2f}€")
- erfolg = konto.auszahlen(50.0)
- print(f"50.00€ ausgezahlt? {erfolg} (sollte False sein) -> Stand: {konto.kontostand}€")
+ erfolg = konto.auszahlen(50.0)
+ print(f"50.00€ ausgezahlt? {erfolg} (sollte False sein) -> Stand: {konto.kontostand:.2f}€")
- erfolg = konto.auszahlen(10.0)
- print(f"10.00€ ausgezahlt? {erfolg} -> Stand: {konto.kontostand}€")
+ erfolg = konto.auszahlen(10.0)
+ print(f"10.00€ ausgezahlt? {erfolg} -> Stand: {konto.kontostand:.2f}€")
+ else:
+ print("💡 Hinweis: Implementiere erst die TODOs, um die Ausgabe zu sehen!")
diff --git a/02_init_und_self/index.html b/02_init_und_self/index.html
new file mode 100644
index 0000000..d9cc948
--- /dev/null
+++ b/02_init_und_self/index.html
@@ -0,0 +1,171 @@
+
+
+
+
+
+ Kapitel 02: Konstruktor __init__ und self
+
+
+
+
+
+
+
+
Kapitel 02
+
Der Konstruktor __init__ & das geheimnisvolle self 💳
+
Lerne, wie Objekte direkt beim Erstellen startklar gemacht werden und baue eine Taschengeld-Konto App.
+
+
+
+
+
+
+
+
1. Warum brauchen wir __init__?
+
+
+ In Kapitel 01 mussten wir jedes Attribut mühsam von Hand setzen:
+
+
+
+
bello = Haustier()
+bello.name = "Bello"
+bello.alter = 3# Was passiert, wenn man hier das Alter vergisst? -> Programm stürzt ab!
+
+
+
+ Deshalb gibt es den Konstruktor__init__. Er wird von Python automatisch aufgerufen, sobald ein neues Objekt erstellt wird!
+
+
+
+
🏗️ Die Geburtsurkunde-Analogie:
+ Wenn ein neues Objekt "geboren" wird, muss es sofort seine grundlegenden Daten erhalten (Name, Startwert). __init__ ist wie das Ausfüllen des Datenblattes bei der Geburt – danach ist das Objekt sofort einsatzbereit!
+
+
+
+
+
+
2. Was bedeutet self?
+
+
+ Das Wörtchen self steht auf Deutsch für "ich selbst" bzw. "dieses konkrete Objekt hier".
+
+
+
+
+
+
+
+
+
+ Python
+
+
classBankkonto:
+ def__init__(self, inhaber, kontostand=0.0):
+ self.inhaber = inhaber# Speichere 'inhaber' im Attribut DIESES Objekts
+ self.kontostand = kontostand# Speichere 'kontostand' in MEINEM Speicher
+
+# Verwendung:
+konto_anna = Bankkonto("Anna", 50.0)
+konto_ben = Bankkonto("Ben") # Verwendet den Standardwert 0.0
+
+
+
+
💡 Warum self.inhaber = inhaber?
+ Links vom Gleichheitszeichen steht self.inhaber – das ist die Variable, die am Objekt dauerhaft gespeichert bleibt. Rechts steht inhaber – das ist nur der temporäre Übergabeparameter der Funktion.
+
+
+
+
+
+
3. Häufige Stolperfallen beim Konstruktor
+
+
+
⚠️ Fehler 1: Doppel-Unterstrich vs. Einzel-Unterstrich
+ Es heißt __init__ mit zwei Unterstrichen davor und danach (Dunder), NICHT _init_! Wenn du nur einen Unterstrich schreibst, ignoriert Python die Methode einfach.
+
+
+
+
⚠️ Fehler 2: self im Methodenkopf vergessen
+ Jede Methode in einer Klasse muss als allerersten Parameter self haben:
+ def einzahlen(self, betrag): ✓
+ def einzahlen(betrag): ✗ (Führt zu TypeError!)
+
+
+
+
+
+
4. Deine Aufgaben in aufgabe.py
+
+
Öffne die Datei 02_init_und_self/aufgabe.py:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
💡 Lösungshinweise (Aufklappen bei Bedarf)
+
+
+ Tipp zu TODO 3 (Auszahlen mit Absicherung)
+
Führe im Terminal im Ordner 02_init_und_self folgenden Befehl aus:
+
+
+ Terminal
+
+
python3 test_aufgabe.py
+
+
+
+
+
+
+
+
+
diff --git a/03_methoden_und_verhalten/README.md b/03_methoden_und_verhalten/README.md
index 2791da9..2883b3f 100644
--- a/03_methoden_und_verhalten/README.md
+++ b/03_methoden_und_verhalten/README.md
@@ -56,6 +56,16 @@ class Spieler:
---
+## ⚠️ Typische Stolperfallen in diesem Kapitel
+
+1. **Grenzen beachten (Min/Max Clamping):**
+ - Lebenspunkte dürfen nach Schaden nie negativ werden: `if self.leben < 0: self.leben = 0`
+ - Lebenspunkte dürfen nach Heilung nie über `max_leben` steigen: `self.leben = min(self.max_leben, self.leben + heilung)`
+2. **Besiegte Objekte können nicht mehr handeln:**
+ - Vor Aktionen wie Angreifen oder Heilen immer prüfen: `if not self.ist_am_leben: return False` bzw. `return 0`
+
+---
+
## 🎯 Deine Aufgabe: Das RPG-Duell
In `aufgabe.py` erstellst du eine Klasse `Held` für ein Rollenspiel:
diff --git a/03_methoden_und_verhalten/aufgabe.py b/03_methoden_und_verhalten/aufgabe.py
index bed2842..2060b3f 100644
--- a/03_methoden_und_verhalten/aufgabe.py
+++ b/03_methoden_und_verhalten/aufgabe.py
@@ -8,7 +8,8 @@ In dieser Aufgabe programmierst du eine Klasse 'Held' für ein Rollenspiel.
class Held:
# ==========================================================================
# TODO 1: Konstruktor __init__(self, name, leben=100, angriffskraft=15)
- # Speichere:
+ #
+ # Speichere die folgenden Attribute an self:
# - self.name = name
# - self.leben = leben
# - self.max_leben = leben (das maximale Leben entspricht dem Startleben)
@@ -21,14 +22,15 @@ class Held:
# ==========================================================================
# TODO 2: Methode "schaden_erleiden(self, schaden)"
- # Regeln:
- # 1. Wenn der Held bereits besiegt ist (not self.ist_am_leben) oder schaden <= 0:
- # - Es passiert nichts, gib 0 zurück.
- # 2. Ziehe 'schaden' von 'self.leben' ab.
- # 3. Wenn 'self.leben' <= 0 wird:
- # - Setze 'self.leben' genau auf 0.
- # - Setze 'self.ist_am_leben' auf False.
- # 4. Gib den erlittenen Schaden (int/float) zurück.
+ #
+ # Schritt-für-Schritt:
+ # 1. Wenn der Held schon tot ist (not self.ist_am_leben) oder schaden <= 0:
+ # - return 0
+ # 2. Berechne den Schaden und ziehe ihn von self.leben ab.
+ # 3. Wenn self.leben <= 0 wird:
+ # - setze self.leben = 0
+ # - setze self.ist_am_leben = False
+ # 4. Gib den erlittenen Schaden zurück (z.B. return schaden).
# ==========================================================================
def schaden_erleiden(self, schaden):
# Schreibe hier deinen Code für TODO 2:
@@ -36,14 +38,16 @@ class Held:
# ==========================================================================
# TODO 3: Methode "heilen(self, heilung)"
- # Regeln:
- # 1. Wenn der Held besiegt ist (not self.ist_am_leben) oder heilung <= 0:
- # - Tote Helden können nicht geheilt werden! Gib 0 zurück.
- # 2. Erhöhe das Leben um 'heilung', aber ACHTUNG:
- # - 'self.leben' darf niemals größer als 'self.max_leben' werden!
- # - Beispiel: Wenn leben=90, max_leben=100 und heilung=20:
- # Das Leben wird 100 (nicht 110) und die tatsächliche Heilung war 10.
- # 3. Gib die tatsächlich geheilte Menge an Lebenspunkten zurück.
+ #
+ # Schritt-für-Schritt:
+ # 1. Wenn der Held tot ist (not self.ist_am_leben) oder heilung <= 0:
+ # - return 0 (Tote können nicht geheilt werden!)
+ # 2. Merke dir das aktuelle Leben: alter_wert = self.leben
+ # 3. Erhöhe das Leben, aber maximal bis self.max_leben:
+ # self.leben = min(self.max_leben, self.leben + heilung)
+ # 4. Berechne, wie viel tatsächlich geheilt wurde:
+ # tatsaechlich_geheilt = self.leben - alter_wert
+ # 5. Gib tatsaechlich_geheilt zurück.
# ==========================================================================
def heilen(self, heilung):
# Schreibe hier deinen Code für TODO 3:
@@ -52,13 +56,15 @@ class Held:
# ==========================================================================
# TODO 4: Methode "angreifen(self, gegner)"
# Parameter 'gegner' ist ein anderes Held-Objekt!
- # Regeln:
- # 1. Prüfe, ob BEIDE Helden noch am Leben sind (self.ist_am_leben und gegner.ist_am_leben).
+ #
+ # Schritt-für-Schritt:
+ # 1. Prüfe, ob BEIDE Helden leben: self.ist_am_leben and gegner.ist_am_leben
# 2. Wenn ja:
- # - Rufe auf dem 'gegner' die Methode 'schaden_erleiden' auf mit self.angriffskraft als Wert.
- # - Gib True zurück.
- # 3. Wenn einer von beiden (oder beide) nicht mehr am Leben ist:
- # - Greife nicht an und gib False zurück.
+ # - Rufe auf dem Gegner schaden_erleiden auf:
+ # gegner.schaden_erleiden(self.angriffskraft)
+ # - Gib True zurück (Angriff erfolgreich).
+ # 3. Wenn einer von beiden besiegt ist:
+ # - Gib False zurück.
# ==========================================================================
def angreifen(self, gegner):
# Schreibe hier deinen Code für TODO 4:
@@ -66,6 +72,7 @@ class Held:
# ==========================================================================
# TODO 5: Methode "status_text(self)"
+ #
# Gibt einen formatierten String zurück:
# Wenn am Leben:
# "[{self.name}] HP: {self.leben}/{self.max_leben} | Kraft: {self.angriffskraft} | Status: Lebendig"
@@ -79,23 +86,27 @@ class Held:
# ==============================================================================
# Kampfsimulator zum Ausprobieren:
+# (Ausführen mit 'python3 aufgabe.py')
# ==============================================================================
if __name__ == "__main__":
print("⚔️ --- ARENA DER HELDEN --- ⚔️")
ritter = Held("Arthur", leben=80, angriffskraft=20)
drache = Held("Feuerspei", leben=120, angriffskraft=25)
- print(ritter.status_text())
- print(drache.status_text())
+ if hasattr(ritter, "name") and ritter.name:
+ print(ritter.status_text())
+ print(drache.status_text())
- print("\n--- Runde 1 ---")
- ritter.angreifen(drache)
- print(drache.status_text())
+ print("\n--- Runde 1 ---")
+ ritter.angreifen(drache)
+ print(drache.status_text())
- drache.angreifen(ritter)
- print(ritter.status_text())
+ drache.angreifen(ritter)
+ print(ritter.status_text())
- print("\n--- Arthur trinkt einen Heiltrank ---")
- geheilt = ritter.heilen(15)
- print(f"Arthur heilt sich um {geheilt} HP!")
- print(ritter.status_text())
+ print("\n--- Arthur trinkt einen Heiltrank ---")
+ geheilt = ritter.heilen(15)
+ print(f"Arthur heilt sich um {geheilt} HP!")
+ print(ritter.status_text())
+ else:
+ print("💡 Hinweis: Implementiere erst die TODOs, um die Arena zu starten!")
diff --git a/03_methoden_und_verhalten/index.html b/03_methoden_und_verhalten/index.html
new file mode 100644
index 0000000..e501f41
--- /dev/null
+++ b/03_methoden_und_verhalten/index.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+ Kapitel 03: Methoden und Verhalten
+
+
+
+
+
+
+
+
Kapitel 03
+
Methoden & Verhalten: Wenn Objekte lebendig werden ⚔️
+
Lass Objekte aktiv handeln und miteinander interagieren in einem rundenbasierten RPG-Heldenduell.
+
+
+
+
+
+
+
+
1. Was sind Methoden?
+
+
+ Bisher haben unsere Klassen vor allem Daten gespeichert. Aber in der objektorientierten Programmierung haben Objekte auch Verhalten. Funktionen, die zu einer Klasse gehören, nennt man Methoden.
+
+
+
+
+
+
+
+
+
+ Python
+
+
classZauberer:
+ def__init__(self, name, mana=50):
+ self.name = name
+ self.mana = mana
+
+ # Eine Methode gehört dem Zauberer:
+ defzauberspruch_wirken(self, kosten):
+ ifself.mana >= kosten:
+ self.mana -= kosten
+ returnTrue
+ returnFalse
+
+
+
+
+
+
2. Wenn zwei Objekte miteinander interagieren
+
+
+ Besonders spannend wird es, wenn eine Methode eines Objekts ein anderes Objekt als Parameter bekommt (z.B. ritter.angreifen(drache)).
+
+
+
+
🤝 Die Duell-Analogie:
+ In angreifen(self, gegner) ist self der Angreifer (z.B. Arthur) und gegner ist das Ziel (z.B. der Drache). Arthur ruft gegner.schaden_erleiden(self.angriffskraft) auf. So beeinflussen sich die Objekte gegenseitig!
+
+ Lebenspunkte dürfen niemals unter 0 fallen (ein besiegter Held hat 0 HP, nicht -15 HP) und bei Heilung niemals über max_leben steigen.
+
+
+
+
+
+
3. Deine Aufgaben in aufgabe.py
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
💡 Lösungshinweise (Aufklappen bei Bedarf)
+
+
+ Tipp zu TODO 3 (Heilung begrenzen)
+
+
+
defheilen(self, heilung):
+ ifnotself.ist_am_lebenorheilung <= 0:
+ return0
+ alter_wert = self.leben
+ self.leben = min(self.max_leben, self.leben + heilung)
+ returnself.leben - alter_wert# Wie viel wurde wirklich geheilt?
+
+
+
+
+
+
+
+
4. Lösung überprüfen
+
Führe im Terminal im Ordner 03_methoden_und_verhalten folgenden Befehl aus:
+
+
+ Terminal
+
+
python3 test_aufgabe.py
+
+
+
+
+
+
+
+
+
diff --git a/04_str_und_darstellung/README.md b/04_str_und_darstellung/README.md
index d121e0d..1e4026d 100644
--- a/04_str_und_darstellung/README.md
+++ b/04_str_und_darstellung/README.md
@@ -60,6 +60,16 @@ class Schultasche:
---
+## ⚠️ Stolperfallen bei `__str__`
+
+1. **`__str__` muss immer einen `str` zurückgeben (`return`), NIEMALS `print`:**
+ - ❌ `def __str__(self): print(self.name)` (Falsch!)
+ - ✅ `def __str__(self): return str(self.name)` (Richtig!)
+2. **Unterstriche beachten:**
+ - Zwei Unterstriche vor und nach `str`: `__str__`.
+
+---
+
## 🎯 Deine Aufgabe: Der Supermarkt-Kassenzettel
In `aufgabe.py` programmierst du zwei Klassen:
diff --git a/04_str_und_darstellung/aufgabe.py b/04_str_und_darstellung/aufgabe.py
index 445cb0d..24e767f 100644
--- a/04_str_und_darstellung/aufgabe.py
+++ b/04_str_und_darstellung/aufgabe.py
@@ -19,6 +19,7 @@ class Artikel:
# TODO 2: Methode "gesamtpreis(self)"
# Gibt den Preis für diesen Artikel multipliziert mit der Anzahl zurück.
# Beispiel: 3 Äpfel à 0.50€ -> 1.50
+ # Tipp: return self.preis * self.anzahl
# ==========================================================================
def gesamtpreis(self):
# Schreibe hier deinen Code für TODO 2:
@@ -26,11 +27,10 @@ class Artikel:
# ==========================================================================
# TODO 3: Dunder-Methode "__str__(self)"
- # Gibt einen String im folgenden Format zurück:
+ # Gibt einen formatierten String zurück:
# "{anzahl}x {name} (je {preis:.2f} €) = {gesamtpreis:.2f} €"
#
- # Beispiel:
- # Bei name="Milch", preis=1.29, anzahl=2:
+ # Beispiel: Bei name="Milch", preis=1.29, anzahl=2:
# -> "2x Milch (je 1.29 €) = 2.58 €"
# ==========================================================================
def __str__(self):
@@ -50,7 +50,7 @@ class Warenkorb:
# ==========================================================================
# TODO 5: Methode "artikel_hinzufuegen(self, artikel)"
- # Fügt das übergebene Artikel-Objekt an 'self.artikel_liste' an (.append).
+ # Hängt das übergebene Artikel-Objekt an 'self.artikel_liste' an (.append).
# ==========================================================================
def artikel_hinzufuegen(self, artikel):
# Schreibe hier deinen Code für TODO 5:
@@ -59,8 +59,13 @@ class Warenkorb:
# ==========================================================================
# TODO 6: Methode "gesamtsumme(self)"
# Berechnet die Summe der Gesamtpreise aller Artikel in self.artikel_liste
- # und gibt diese als float zurück. (Tipp: Schleife oder sum())
- # Bei leerem Warenkorb soll 0.0 zurückgegeben werden.
+ # und gibt diese als float zurück.
+ #
+ # Tipp mit Schleife:
+ # total = 0.0
+ # for item in self.artikel_liste:
+ # total += item.gesamtpreis()
+ # return total
# ==========================================================================
def gesamtsumme(self):
# Schreibe hier deinen Code für TODO 6:
@@ -76,8 +81,7 @@ class Warenkorb:
# --------------------
# Gesamtsumme: 5.07 €
#
- # Tipp: Baue eine Liste von Zeilen und verbinde sie mit "\n".join(...)
- # Die Zeilen für die Artikel erhältst du einfach mit str(artikel)!
+ # Tipp: Baue eine Liste von Zeilen und verbinde sie am Ende mit "\n".join(...)
# ==========================================================================
def bon_text(self):
# Schreibe hier deinen Code für TODO 7:
@@ -86,6 +90,7 @@ class Warenkorb:
# ==============================================================================
# Hauptprogramm zum Ausprobieren:
+# (Ausführen mit 'python3 aufgabe.py')
# ==============================================================================
if __name__ == "__main__":
print("🛒 --- SUPERMARKT EINKAUF --- 🛒")
@@ -95,11 +100,10 @@ if __name__ == "__main__":
a2 = Artikel("Brot", 2.49, 1)
a3 = Artikel("Schokolade", 0.99, 3)
- korb.artikel_hinzufuegen(a1)
- korb.artikel_hinzufuegen(a2)
- korb.artikel_hinzufuegen(a3)
-
- if korb.artikel_liste:
+ if hasattr(korb, "artikel_liste"):
+ korb.artikel_hinzufuegen(a1)
+ korb.artikel_hinzufuegen(a2)
+ korb.artikel_hinzufuegen(a3)
print(korb.bon_text())
else:
- print("Hinweis: Implementiere die TODOs, um den Kassenbon zu drucken!")
+ print("💡 Hinweis: Implementiere die TODOs, um den Kassenbon zu drucken!")
diff --git a/04_str_und_darstellung/index.html b/04_str_und_darstellung/index.html
new file mode 100644
index 0000000..6fae5f0
--- /dev/null
+++ b/04_str_und_darstellung/index.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+ Kapitel 04: __str__ und Darstellung
+
+
+
+
+
+
+
+
Kapitel 04
+
Schöne Ausgaben mit __str__ & Objektlisten 🧾
+
Lerne, wie du bestimmst, was beim print(objekt) erscheint und wie Objekte andere Objekte in Listen verwalten.
+
+
+
+
+
+
+
+
1. Warum sieht print(objekt) standardmäßig so hässlich aus?
+
+
+ Wenn du versuchst, ein Objekt ohne Dunder-Methode zu drucken:
+
+ Python weiß ohne deine Hilfe nicht, wie du dein Objekt darstellen möchtest.
+
+
+
+
✨ Die Magie von __str__:
+ Sobald du in deiner Klasse eine Methode def __str__(self): definierst, ruft Python diese automatisch auf, wann immer das Objekt zu Text umgewandelt wird (bei print(), str() oder in f-Strings)!
+
+
+
+
+
+
+
+
+
+ Python
+
+
classBuch:
+ def__init__(self, titel, autor):
+ self.titel = titel
+ self.autor = autor
+
+ def__str__(self):
+ returnf"'{self.titel}' von {self.autor}"# MUSS ein String sein!
+
+mein_buch = Buch("Harry Potter", "J.K. Rowling")
+print(mein_buch) # Ausgabe: 'Harry Potter' von J.K. Rowling
+
+
+
+
+
+
2. Objekte in Listen verwalten
+
+
+ Eine Klasse kann als Attribut eine Liste von anderen Objekten haben:
+
+
+
+
🛒 Der Warenkorb:
+ Ein Warenkorb besitzt eine Liste self.artikel_liste = []. Wenn du einen Artikel hinzufügst, landet das ganze Artikel-Objekt in der Liste!
+
+
+
+
+
+
3. Deine Aufgaben in aufgabe.py
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
💡 Lösungshinweise (Aufklappen bei Bedarf)
+
+
+ Tipp zu TODO 7 (Kassenzettel zusammensetzen)
+
Führe im Terminal im Ordner 04_str_und_darstellung folgenden Befehl aus:
+
+
+ Terminal
+
+
python3 test_aufgabe.py
+
+
+
+
+
+
+
+
+
diff --git a/05_objekte_kombinieren/aufgabe.py b/05_objekte_kombinieren/aufgabe.py
index c8436d9..6888c38 100644
--- a/05_objekte_kombinieren/aufgabe.py
+++ b/05_objekte_kombinieren/aufgabe.py
@@ -20,7 +20,11 @@ class Song:
# TODO 2: Methode "formatierte_dauer(self)"
# Rechnet 'self.dauer_sekunden' in Minuten und Sekunden um und gibt einen
# String im Format "MM:SS" zurück (z.B. 215 -> "03:35", 70 -> "01:10").
- # Tipp: Verwende // 60 und % 60 sowie f"{minuten:02d}:{sekunden:02d}"
+ #
+ # Tipp:
+ # minuten = self.dauer_sekunden // 60
+ # sekunden = self.dauer_sekunden % 60
+ # return f"{minuten:02d}:{sekunden:02d}"
# ==========================================================================
def formatierte_dauer(self):
# Schreibe hier deinen Code für TODO 2:
@@ -28,8 +32,8 @@ class Song:
# ==========================================================================
# TODO 3: Dunder-Methode "__str__(self)"
- # Gibt einen String im folgenden Format zurück:
- # '"{titel}" von {kuenstler} ({dauer})'
+ # Gibt einen String im Format zurück:
+ # '"{titel}" von {kuenstler} ({formatierte_dauer})'
#
# Beispiel: '"Flowers" von Miley Cyrus (03:20)'
# ==========================================================================
@@ -50,7 +54,7 @@ class Playlist:
# ==========================================================================
# TODO 5: Methode "song_hinzufuegen(self, song)"
- # Hängt das übergebene Song-Objekt an 'self.songs' an.
+ # Hängt das übergebene Song-Objekt an 'self.songs' an (.append).
# ==========================================================================
def song_hinzufuegen(self, song):
# Schreibe hier deinen Code für TODO 5:
@@ -58,7 +62,7 @@ class Playlist:
# ==========================================================================
# TODO 6: Methode "anzahl_songs(self)"
- # Gibt die Anzahl der Songs in der Playlist als Integer zurück.
+ # Gibt die Anzahl der Songs in der Playlist als Integer zurück (len(self.songs)).
# ==========================================================================
def anzahl_songs(self):
# Schreibe hier deinen Code für TODO 6:
@@ -68,6 +72,12 @@ class Playlist:
# TODO 7: Methode "gesamtdauer_sekunden(self)"
# Gibt die Summe der Sekunden aller Songs in der Playlist zurück.
# Bei leerer Playlist: 0
+ #
+ # Tipp:
+ # total = 0
+ # for s in self.songs:
+ # total += s.dauer_sekunden
+ # return total
# ==========================================================================
def gesamtdauer_sekunden(self):
# Schreibe hier deinen Code für TODO 7:
@@ -96,6 +106,7 @@ class Playlist:
# ==============================================================================
# Hauptprogramm zum Ausprobieren:
+# (Ausführen mit 'python3 aufgabe.py')
# ==============================================================================
if __name__ == "__main__":
print("🎧 --- MEINE PLAYLIST --- 🎧")
@@ -106,18 +117,21 @@ if __name__ == "__main__":
s3 = Song("Anti-Hero", "Taylor Swift", 201)
s4 = Song("As It Was", "Harry Styles", 167)
- meine_hits.song_hinzufuegen(s1)
- meine_hits.song_hinzufuegen(s2)
- meine_hits.song_hinzufuegen(s3)
- meine_hits.song_hinzufuegen(s4)
+ if hasattr(meine_hits, "songs"):
+ meine_hits.song_hinzufuegen(s1)
+ meine_hits.song_hinzufuegen(s2)
+ meine_hits.song_hinzufuegen(s3)
+ meine_hits.song_hinzufuegen(s4)
- print(f"Playlist: {meine_hits.name} ({meine_hits.anzahl_songs()} Songs)")
- print(f"Gesamtlaufzeit: {meine_hits.gesamtdauer_sekunden()} Sekunden")
+ print(f"Playlist: {meine_hits.name} ({meine_hits.anzahl_songs()} Songs)")
+ print(f"Gesamtlaufzeit: {meine_hits.gesamtdauer_sekunden()} Sekunden")
- laengster = meine_hits.laengster_song()
- if laengster:
- print(f"Längster Song: {laengster}")
+ laengster = meine_hits.laengster_song()
+ if laengster:
+ print(f"Längster Song: {laengster}")
- print("\nSongs von Taylor Swift:")
- for s in meine_hits.finde_songs_von("taylor swift"):
- print(f"- {s}")
+ print("\nSongs von Taylor Swift:")
+ for s in meine_hits.finde_songs_von("taylor swift"):
+ print(f"- {s}")
+ else:
+ print("💡 Hinweis: Implementiere die TODOs, um die Playlist zu testen!")
diff --git a/05_objekte_kombinieren/index.html b/05_objekte_kombinieren/index.html
new file mode 100644
index 0000000..9f11649
--- /dev/null
+++ b/05_objekte_kombinieren/index.html
@@ -0,0 +1,150 @@
+
+
+
+
+
+ Kapitel 05: Komposition und Playlists
+
+
+
+
+
+
+
+
Kapitel 05
+
Komposition: Objekte kombinieren & filtern 🎵
+
Baue einen eigenen Spotify-Playlist-Manager und lerne, wie Objekte andere Objekte suchen, berechnen und filtern.
+
+
+
+
+
+
+
+
1. Was ist Komposition?
+
+
+ In großen Anwendungen (wie Spotify, Netflix oder Videospielen) arbeiten viele Klassen zusammen. Wenn eine Klasse Instanzen einer anderen Klasse beinhaltet, nennt man das Komposition (oder *"hat-ein"-Beziehung*):
+
+
+
+
Eine Playlisthat viele Songs.
+
Ein Kinohat viele Säle und Filme.
+
+
+
+
🎧 Die Spotify-Analogie:
+ Ein Song speichert seinen Titel, den Künstler und die Länge in Sekunden. Die Playlist kümmert sich um die Gesamtübersicht: Wie viele Songs gibt es? Wie lange dauert die Playlist insgesamt? Gibt es Lieder von Taylor Swift?
+
+
+
+
+
+
2. Nützliche Python-Kniffe
+
+
⏱️ Sekunden in "MM:SS" umrechnen
+
+ Mit Ganzzahldivision // und Modulo % rechnen wir Sekunden in Minuten um:
+
Lerne Schritt für Schritt, wie du eigene Klassen baust, Methoden nutzt und komplexe Programme strukturierst.
+
+
+
+
+
+
+
+
👋 Willkommen zu deiner Übungsreihe!
+
+ Bisher hast du in Python schon viel gelernt: Variablen, Schleifen, Bedingungen, Listen, Dictionaries und Funktionen.
+ Jetzt machen wir den nächsten großen Schritt in der Softwareentwicklung: Klassen & Objekte!
+
+
+ Mit Klassen kannst du zusammengehörige Daten und Aktionen an einem Ort bündeln. Fast jede moderne App (ob Instagram, Spotify oder Computerspiele) basiert auf objektorientierter Programmierung.
+
+
+
+
🏗️ Die Grundidee in einem Satz:
+ Eine Klasse ist wie ein Bauplan (oder eine Plätzchen-Ausstechform). Ein Objekt ist das fertige Haus (oder das gebackene Plätzchen), das nach diesem Bauplan entstanden ist!
+
Wähle das nächste offene Kapitel aus der Liste oben.
+
Lies die Erklärungen und schau dir die Codebeispiele und „Stolperfallen“ an.
+
Öffne die aufgabe.py im entsprechenden Kapitelordner und löse die TODOs.
+
+ Führe im Terminal den automatischen Test aus:
+
+
+ Terminal
+
+
python3 test_aufgabe.py
+
+
+
Wenn alle Tests mit OK durchlaufen, hast du das Kapitel erfolgreich gemeistert! 🎉
+
+
+
+
💡 Gesamten Fortschritt auf einen Blick prüfen:
+ Du kannst jederzeit im Hauptordner folgenden Befehl ausführen, um zu sehen, wie viele Kapitel du schon gelöst hast:
+
+
python3 test_all.py
+
+
+
+
+
+
+
🩺 Erste Hilfe & Häufige Fragen
+
+
+ ❌ Fehlermeldung: TypeError: ... takes 0 positional arguments but 1 was given
+
+
Ursache: Du hast bei einer Methode in deiner Klasse das self im Methodenkopf vergessen!
+
Lösung: Schreibe def meine_methode(self): statt def meine_methode():. Python übergibt bei Methodenaufrufen immer automatisch das Objekt selbst als erstes Argument.
+
+
+
+
+ ❌ Fehlermeldung: AttributeError: 'NoneType' object has no attribute '...'
+
+
Ursache: Eine Funktion oder Methode hat nichts zurückgegeben (also None), und du versuchst, auf ein Attribut davon zuzugreifen.
+
Lösung: Prüfe, ob du am Ende der Funktion das return objekt vergessen hast!
+
+
+
+
+ ❌ Der Test schlägt fehl, obwohl ich die richtige Ausgabe in der Konsole sehe?
+
+
Ursache: Du hast vermutlich print(...) verwendet, anstatt den Wert mit return ... zurückzugeben.
+
Lösung: Die automatischen Tests prüfen den Rückgabewert (return) deiner Funktionen/Methoden, nicht das, was auf dem Bildschirm ausgegeben wird.