Erweitere Übungsreihe um detaillierte Erklärungen, Stolperfallen-Guides und modernes HTML-Lernportal
This commit is contained in:
parent
ce35e7d479
commit
fbaec82182
19 changed files with 1811 additions and 141 deletions
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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!")
|
||||
|
|
|
|||
192
01_einstieg_klassen/index.html
Normal file
192
01_einstieg_klassen/index.html
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 01: Einstieg in Klassen</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;">Kapitel 01</span>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel 01</div>
|
||||
<h1>Die erste Klasse: Bauplan vs. Objekt 🐶</h1>
|
||||
<p>Verstehe den Unterschied zwischen einer Klasse und einer Instanz und baue deine ersten Haustier-Objekte.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Theorie Card -->
|
||||
<section class="card">
|
||||
<h2>1. Die wichtigste Idee: Bauplan vs. Haus</h2>
|
||||
|
||||
<p>
|
||||
In Python ist alles, was du bisher kennengelernt hast (Zahlen, Strings, Listen, Dictionaries), im Grunde ein <strong>Objekt</strong>. Doch jetzt lernst du, wie du <strong>deine ganz eigenen Datentypen</strong> erfindest!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏗️ Die Plätzchenform-Analogie:</div>
|
||||
<p>Stell dir das Backen vor:</p>
|
||||
<ul style="margin-left: 20px;">
|
||||
<li>Die <strong>Klasse (<code>class</code>)</strong> ist die <strong>Ausstechform</strong>. Sie legt fest: Jedes Plätzchen hat einen Kopf, zwei Arme und zwei Beine. Die Form selbst kann man aber nicht essen.</li>
|
||||
<li>Das <strong>Objekt (Instanz)</strong> ist das <strong>echte Plätzchen</strong>, das du aus dem Teig ausstichst. Ein Plätzchen bekommt Schokoglasur, das andere Zuckerstreusel. Beide stammen aus derselben Form, sind aber eigenständig!</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h3>Warum nicht einfach Dictionaries?</h3>
|
||||
<p>Ein Dictionary hat keine feste Struktur – man vertippt sich leicht:</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 (Problem mit Dictionaries)</span>
|
||||
</div>
|
||||
<pre><span class="var">tier1</span> = {<span class="str">"name"</span>: <span class="str">"Bello"</span>, <span class="str">"tierart"</span>: <span class="str">"Hund"</span>, <span class="str">"alter"</span>: <span class="num">3</span>}
|
||||
<span class="var">tier2</span> = {<span class="str">"name"</span>: <span class="str">"Mimi"</span>, <span class="str">"art"</span>: <span class="str">"Katze"</span>, <span class="str">"alter"</span>: <span class="num">5</span>} <span class="cm"># Ups! 'art' statt 'tierart'!</span>
|
||||
<span class="cm"># Ein Programm würde hier abstürzen, weil tier2["tierart"] nicht existiert!</span></pre>
|
||||
</div>
|
||||
|
||||
<p>Mit einer <strong>Klasse</strong> definierst du eine klare, wiederverwendbare Struktur.</p>
|
||||
</section>
|
||||
|
||||
<!-- Syntax Card -->
|
||||
<section class="card">
|
||||
<h2>2. Wie definiert und nutzt man eine Klasse?</h2>
|
||||
|
||||
<p>Eine einfache Klasse erstellst du mit dem Schlüsselwort <code>class</code>:</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</span>
|
||||
</div>
|
||||
<pre><span class="cm"># 1. Bauplan definieren:</span>
|
||||
<span class="kw">class</span> <span class="fn">Auto</span>:
|
||||
<span class="kw">pass</span> <span class="cm"># pass bedeutet: Hier steht erst mal kein weiterer Code</span>
|
||||
|
||||
<span class="cm"># 2. Ein Objekt erzeugen (Instanziierung):</span>
|
||||
<span class="var">mein_auto</span> = <span class="fn">Auto</span>()
|
||||
|
||||
<span class="cm"># 3. Eigenschaften (Attribute) mit dem Punkt (.) setzen:</span>
|
||||
<span class="var">mein_auto</span>.<span class="attr">farbe</span> = <span class="str">"Rot"</span>
|
||||
<span class="var">mein_auto</span>.<span class="attr">marke</span> = <span class="str">"VW"</span>
|
||||
<span class="var">mein_auto</span>.<span class="attr">ps</span> = <span class="num">110</span>
|
||||
|
||||
<span class="cm"># 4. Werte wieder abfragen:</span>
|
||||
<span class="fn">print</span>(<span class="var">mein_auto</span>.<span class="attr">farbe</span>) <span class="cm"># Gibt "Rot" aus</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Häufige Stolperfalle: Klassenname Großschreiben!</div>
|
||||
In Python schreibt man Klassennamen standardmäßig in <strong>CamelCase</strong> mit großem Anfangsbuchstaben (z.B. <code>Haustier</code>, <code>BankKonto</code>), während Variablen und Funktionen klein geschrieben werden (z.B. <code>mein_haustier</code>, <code>erstelle_tier()</code>).
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben Card -->
|
||||
<section class="card">
|
||||
<h2>3. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>01_einstieg_klassen/aufgabe.py</code> und bearbeite die nummerierten 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:</strong> Definiere die Klasse <code>Haustier</code> mit <code>pass</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2">
|
||||
<label for="t2" class="task-label">
|
||||
<strong>TODO 2:</strong> Funktion <code>erstelle_bello()</code>: Erzeuge ein Haustier-Objekt mit <code>name="Bello"</code>, <code>tierart="Hund"</code>, <code>alter=3</code> und gib es mit <code>return</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:</strong> Funktion <code>erstelle_mimi()</code>: Erzeuge ein Haustier-Objekt mit <code>name="Mimi"</code>, <code>tierart="Katze"</code>, <code>alter=5</code> und gib es 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:</strong> Funktion <code>steckbrief_text(haustier)</code>: Gibt einen f-String zurück: <code>"{haustier.name} ist ein(e) {haustier.tierart} und ist {haustier.alter} Jahre alt."</code>
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5">
|
||||
<label for="t5" class="task-label">
|
||||
<strong>TODO 5:</strong> Funktion <code>aelteres_tier(tier1, tier2)</code>: Vergleicht <code>tier1.alter</code> und <code>tier2.alter</code> und gibt das ältere Haustier-Objekt zurück (bei Gleichstand <code>tier1</code>).
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zu TODO 1 & 2 (Objekt erstellen und befüllen)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">class</span> <span class="fn">Haustier</span>:
|
||||
<span class="kw">pass</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">erstelle_bello</span>():
|
||||
<span class="var">tier</span> = <span class="fn">Haustier</span>() <span class="cm"># Neues Objekt erzeugen</span>
|
||||
<span class="var">tier</span>.<span class="attr">name</span> = <span class="str">"Bello"</span>
|
||||
<span class="var">tier</span>.<span class="attr">tierart</span> = <span class="str">"Hund"</span>
|
||||
<span class="var">tier</span>.<span class="attr">alter</span> = <span class="num">3</span>
|
||||
<span class="kw">return</span> <span class="var">tier</span> <span class="cm"># WICHTIG: Das fertige Objekt zurückgeben!</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zu TODO 5 (Tiere vergleichen)</summary>
|
||||
<div class="details-content">
|
||||
<p>Du kannst mit einem einfachen <code>if</code> auf die Attribute der übergebenen Objekte zugreifen:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">if</span> <span class="var">tier2</span>.<span class="attr">alter</span> > <span class="var">tier1</span>.<span class="attr">alter</span>:
|
||||
<span class="kw">return</span> <span class="var">tier2</span>
|
||||
<span class="kw">else</span>:
|
||||
<span class="kw">return</span> <span class="var">tier1</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- Testen & Footer Navigation -->
|
||||
<section class="card">
|
||||
<h2>4. Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal im Ordner <code>01_einstieg_klassen</code> 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="../index.html" class="btn btn-secondary">← Zurück zur Übersicht</a>
|
||||
<a href="../02_init_und_self/index.html" class="btn">Weiter zu Kapitel 02 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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`:
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
erfolg = konto.einzahlen(15.5)
|
||||
print(f"15.50€ eingezahlt? {erfolg} -> Neuer Stand: {konto.kontostand}€")
|
||||
if hasattr(konto, "inhaber") and konto.inhaber:
|
||||
print(konto.info_text())
|
||||
|
||||
erfolg = konto.auszahlen(50.0)
|
||||
print(f"50.00€ ausgezahlt? {erfolg} (sollte False sein) -> Stand: {konto.kontostand}€")
|
||||
erfolg = konto.einzahlen(15.5)
|
||||
print(f"15.50€ eingezahlt? {erfolg} -> Neuer Stand: {konto.kontostand:.2f}€")
|
||||
|
||||
erfolg = konto.auszahlen(10.0)
|
||||
print(f"10.00€ ausgezahlt? {erfolg} -> 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:.2f}€")
|
||||
else:
|
||||
print("💡 Hinweis: Implementiere erst die TODOs, um die Ausgabe zu sehen!")
|
||||
|
|
|
|||
171
02_init_und_self/index.html
Normal file
171
02_init_und_self/index.html
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 02: Konstruktor __init__ und self</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="../01_einstieg_klassen/index.html">Kapitel 01</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel 02</span>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel 02</div>
|
||||
<h1>Der Konstruktor <code>__init__</code> & das geheimnisvolle <code>self</code> 💳</h1>
|
||||
<p>Lerne, wie Objekte direkt beim Erstellen startklar gemacht werden und baue eine Taschengeld-Konto App.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Theorie Card -->
|
||||
<section class="card">
|
||||
<h2>1. Warum brauchen wir <code>__init__</code>?</h2>
|
||||
|
||||
<p>
|
||||
In Kapitel 01 mussten wir jedes Attribut mühsam von Hand setzen:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<pre><span class="var">bello</span> = <span class="fn">Haustier</span>()
|
||||
<span class="var">bello</span>.<span class="attr">name</span> = <span class="str">"Bello"</span>
|
||||
<span class="var">bello</span>.<span class="attr">alter</span> = <span class="num">3</span> <span class="cm"># Was passiert, wenn man hier das Alter vergisst? -> Programm stürzt ab!</span></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Deshalb gibt es den <strong>Konstruktor</strong> <code>__init__</code>. Er wird von Python <strong>automatisch aufgerufen</strong>, sobald ein neues Objekt erstellt wird!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏗️ Die Geburtsurkunde-Analogie:</div>
|
||||
Wenn ein neues Objekt "geboren" wird, muss es sofort seine grundlegenden Daten erhalten (Name, Startwert). <code>__init__</code> ist wie das Ausfüllen des Datenblattes bei der Geburt – danach ist das Objekt sofort einsatzbereit!
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- self Erklärung -->
|
||||
<section class="card">
|
||||
<h2>2. Was bedeutet <code>self</code>?</h2>
|
||||
|
||||
<p>
|
||||
Das Wörtchen <code>self</code> steht auf Deutsch für <strong>"ich selbst"</strong> bzw. <strong>"dieses konkrete Objekt hier"</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</span>
|
||||
</div>
|
||||
<pre><span class="kw">class</span> <span class="fn">Bankkonto</span>:
|
||||
<span class="kw">def</span> <span class="fn">__init__</span>(<span class="var">self</span>, <span class="var">inhaber</span>, <span class="var">kontostand</span>=<span class="num">0.0</span>):
|
||||
<span class="var">self</span>.<span class="attr">inhaber</span> = <span class="var">inhaber</span> <span class="cm"># Speichere 'inhaber' im Attribut DIESES Objekts</span>
|
||||
<span class="var">self</span>.<span class="attr">kontostand</span> = <span class="var">kontostand</span> <span class="cm"># Speichere 'kontostand' in MEINEM Speicher</span>
|
||||
|
||||
<span class="cm"># Verwendung:</span>
|
||||
<span class="var">konto_anna</span> = <span class="fn">Bankkonto</span>(<span class="str">"Anna"</span>, <span class="num">50.0</span>)
|
||||
<span class="var">konto_ben</span> = <span class="fn">Bankkonto</span>(<span class="str">"Ben"</span>) <span class="cm"># Verwendet den Standardwert 0.0</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">💡 Warum <code>self.inhaber = inhaber</code>?</div>
|
||||
Links vom Gleichheitszeichen steht <code>self.inhaber</code> – das ist die Variable, die <strong>am Objekt dauerhaft gespeichert</strong> bleibt. Rechts steht <code>inhaber</code> – das ist nur der temporäre Übergabeparameter der Funktion.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Stolperfallen -->
|
||||
<section class="card">
|
||||
<h2>3. Häufige Stolperfallen beim Konstruktor</h2>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Fehler 1: Doppel-Unterstrich vs. Einzel-Unterstrich</div>
|
||||
Es heißt <code>__init__</code> mit <strong>zwei Unterstrichen</strong> davor und danach (Dunder), NICHT <code>_init_</code>! Wenn du nur einen Unterstrich schreibst, ignoriert Python die Methode einfach.
|
||||
</div>
|
||||
|
||||
<div class="box box-danger">
|
||||
<div class="box-title">⚠️ Fehler 2: <code>self</code> im Methodenkopf vergessen</div>
|
||||
Jede Methode in einer Klasse <strong>muss</strong> als allerersten Parameter <code>self</code> haben:
|
||||
<br><code>def einzahlen(self, betrag):</code> ✓
|
||||
<br><code>def einzahlen(betrag):</code> ✗ (Führt zu <code>TypeError</code>!)
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben -->
|
||||
<section class="card">
|
||||
<h2>4. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<p>Öffne die Datei <code>02_init_und_self/aufgabe.py</code>:</p>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2_1">
|
||||
<label for="t2_1" class="task-label">
|
||||
<strong>TODO 1:</strong> Schreibe <code>__init__(self, inhaber, kontostand=0.0)</code> und binde <code>inhaber</code> und <code>kontostand</code> an <code>self</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2_2">
|
||||
<label for="t2_2" class="task-label">
|
||||
<strong>TODO 2:</strong> Methode <code>einzahlen(self, betrag)</code>: Wenn <code>betrag > 0</code>, erhöhe Kontostand und gib <code>True</code> zurück, sonst <code>False</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2_3">
|
||||
<label for="t2_3" class="task-label">
|
||||
<strong>TODO 3:</strong> Methode <code>auszahlen(self, betrag)</code>: Wenn <code>betrag > 0</code> und <code>self.kontostand >= betrag</code>, ziehe Geld ab und gib <code>True</code> zurück, sonst <code>False</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t2_4">
|
||||
<label for="t2_4" class="task-label">
|
||||
<strong>TODO 4:</strong> Methode <code>info_text(self)</code>: Gibt f-String zurück: <code>"Konto von {self.inhaber}: {self.kontostand:.2f} Euro"</code>.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zu TODO 3 (Auszahlen mit Absicherung)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">auszahlen</span>(<span class="var">self</span>, <span class="var">betrag</span>):
|
||||
<span class="kw">if</span> <span class="var">betrag</span> > <span class="num">0</span> <span class="kw">and</span> <span class="var">self</span>.<span class="attr">kontostand</span> >= <span class="var">betrag</span>:
|
||||
<span class="var">self</span>.<span class="attr">kontostand</span> -= <span class="var">betrag</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>
|
||||
</section>
|
||||
|
||||
<!-- Testen & Footer Navigation -->
|
||||
<section class="card">
|
||||
<h2>5. Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal im Ordner <code>02_init_und_self</code> 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="../01_einstieg_klassen/index.html" class="btn btn-secondary">← Zurück zu Kapitel 01</a>
|
||||
<a href="../03_methoden_und_verhalten/index.html" class="btn">Weiter zu Kapitel 03 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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!")
|
||||
|
|
|
|||
152
03_methoden_und_verhalten/index.html
Normal file
152
03_methoden_und_verhalten/index.html
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 03: Methoden und Verhalten</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="../02_init_und_self/index.html">Kapitel 02</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel 03</span>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel 03</div>
|
||||
<h1>Methoden & Verhalten: Wenn Objekte lebendig werden ⚔️</h1>
|
||||
<p>Lass Objekte aktiv handeln und miteinander interagieren in einem rundenbasierten RPG-Heldenduell.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Theorie Card -->
|
||||
<section class="card">
|
||||
<h2>1. Was sind Methoden?</h2>
|
||||
|
||||
<p>
|
||||
Bisher haben unsere Klassen vor allem Daten gespeichert. Aber in der objektorientierten Programmierung haben Objekte auch <strong>Verhalten</strong>. Funktionen, die zu einer Klasse gehören, nennt man <strong>Methoden</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</span>
|
||||
</div>
|
||||
<pre><span class="kw">class</span> <span class="fn">Zauberer</span>:
|
||||
<span class="kw">def</span> <span class="fn">__init__</span>(<span class="var">self</span>, <span class="var">name</span>, <span class="var">mana</span>=<span class="num">50</span>):
|
||||
<span class="var">self</span>.<span class="attr">name</span> = <span class="var">name</span>
|
||||
<span class="var">self</span>.<span class="attr">mana</span> = <span class="var">mana</span>
|
||||
|
||||
<span class="cm"># Eine Methode gehört dem Zauberer:</span>
|
||||
<span class="kw">def</span> <span class="fn">zauberspruch_wirken</span>(<span class="var">self</span>, <span class="var">kosten</span>):
|
||||
<span class="kw">if</span> <span class="var">self</span>.<span class="attr">mana</span> >= <span class="var">kosten</span>:
|
||||
<span class="var">self</span>.<span class="attr">mana</span> -= <span class="var">kosten</span>
|
||||
<span class="kw">return</span> <span class="kw">True</span>
|
||||
<span class="kw">return</span> <span class="kw">False</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Interaktion zwischen Objekten -->
|
||||
<section class="card">
|
||||
<h2>2. Wenn zwei Objekte miteinander interagieren</h2>
|
||||
|
||||
<p>
|
||||
Besonders spannend wird es, wenn eine Methode eines Objekts ein <strong>anderes Objekt als Parameter</strong> bekommt (z.B. <code>ritter.angreifen(drache)</code>).
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🤝 Die Duell-Analogie:</div>
|
||||
In <code>angreifen(self, gegner)</code> ist <code>self</code> der Angreifer (z.B. Arthur) und <code>gegner</code> ist das Ziel (z.B. der Drache). Arthur ruft <code>gegner.schaden_erleiden(self.angriffskraft)</code> auf. So beeinflussen sich die Objekte gegenseitig!
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-title">⚠️ Wichtig: Logische Grenzen einhalten (Clamping)!</div>
|
||||
Lebenspunkte dürfen niemals unter <code>0</code> fallen (ein besiegter Held hat 0 HP, nicht -15 HP) und bei Heilung niemals über <code>max_leben</code> steigen.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben Card -->
|
||||
<section class="card">
|
||||
<h2>3. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3_1">
|
||||
<label for="t3_1" class="task-label">
|
||||
<strong>TODO 1:</strong> <code>__init__(self, name, leben=100, angriffskraft=15)</code> mit <code>max_leben = leben</code> und <code>ist_am_leben = True</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3_2">
|
||||
<label for="t3_2" class="task-label">
|
||||
<strong>TODO 2:</strong> Methode <code>schaden_erleiden(self, schaden)</code>: Zieht Schaden ab. Fällt das Leben auf/unter 0 -> setze <code>leben = 0</code> und <code>ist_am_leben = False</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3_3">
|
||||
<label for="t3_3" class="task-label">
|
||||
<strong>TODO 3:</strong> Methode <code>heilen(self, heilung)</code>: Erhöht Leben maximal bis <code>max_leben</code> (nur wenn noch am Leben).
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3_4">
|
||||
<label for="t3_4" class="task-label">
|
||||
<strong>TODO 4:</strong> Methode <code>angreifen(self, gegner)</code>: Wenn beide lebendig sind, rufe <code>gegner.schaden_erleiden(self.angriffskraft)</code> auf.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t3_5">
|
||||
<label for="t3_5" class="task-label">
|
||||
<strong>TODO 5:</strong> Methode <code>status_text(self)</code>: Gibt formatierten Status zurück.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zu TODO 3 (Heilung begrenzen)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">heilen</span>(<span class="var">self</span>, <span class="var">heilung</span>):
|
||||
<span class="kw">if</span> <span class="kw">not</span> <span class="var">self</span>.<span class="attr">ist_am_leben</span> <span class="kw">or</span> <span class="var">heilung</span> <= <span class="num">0</span>:
|
||||
<span class="kw">return</span> <span class="num">0</span>
|
||||
<span class="var">alter_wert</span> = <span class="var">self</span>.<span class="attr">leben</span>
|
||||
<span class="var">self</span>.<span class="attr">leben</span> = <span class="fn">min</span>(<span class="var">self</span>.<span class="attr">max_leben</span>, <span class="var">self</span>.<span class="attr">leben</span> + <span class="var">heilung</span>)
|
||||
<span class="kw">return</span> <span class="var">self</span>.<span class="attr">leben</span> - <span class="var">alter_wert</span> <span class="cm"># Wie viel wurde wirklich geheilt?</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- Testen & Footer Navigation -->
|
||||
<section class="card">
|
||||
<h2>4. Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal im Ordner <code>03_methoden_und_verhalten</code> 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="../02_init_und_self/index.html" class="btn btn-secondary">← Zurück zu Kapitel 02</a>
|
||||
<a href="../04_str_und_darstellung/index.html" class="btn">Weiter zu Kapitel 04 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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!")
|
||||
|
|
|
|||
155
04_str_und_darstellung/index.html
Normal file
155
04_str_und_darstellung/index.html
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 04: __str__ und Darstellung</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="../03_methoden_und_verhalten/index.html">Kapitel 03</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel 04</span>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel 04</div>
|
||||
<h1>Schöne Ausgaben mit <code>__str__</code> & Objektlisten 🧾</h1>
|
||||
<p>Lerne, wie du bestimmst, was beim <code>print(objekt)</code> erscheint und wie Objekte andere Objekte in Listen verwalten.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Theorie Card -->
|
||||
<section class="card">
|
||||
<h2>1. Warum sieht <code>print(objekt)</code> standardmäßig so hässlich aus?</h2>
|
||||
|
||||
<p>
|
||||
Wenn du versuchst, ein Objekt ohne Dunder-Methode zu drucken:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<pre><span class="var">mein_buch</span> = <span class="fn">Buch</span>(<span class="str">"Harry Potter"</span>, <span class="str">"J.K. Rowling"</span>)
|
||||
<span class="fn">print</span>(<span class="var">mein_buch</span>) <span class="cm"># Ausgabe: <__main__.Buch object at 0x7fa2b0485d90></span></pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Python weiß ohne deine Hilfe nicht, wie du dein Objekt darstellen möchtest.
|
||||
</p>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">✨ Die Magie von <code>__str__</code>:</div>
|
||||
Sobald du in deiner Klasse eine Methode <code>def __str__(self):</code> definierst, ruft Python diese automatisch auf, wann immer das Objekt zu Text umgewandelt wird (bei <code>print()</code>, <code>str()</code> oder in f-Strings)!
|
||||
</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</span>
|
||||
</div>
|
||||
<pre><span class="kw">class</span> <span class="fn">Buch</span>:
|
||||
<span class="kw">def</span> <span class="fn">__init__</span>(<span class="var">self</span>, <span class="var">titel</span>, <span class="var">autor</span>):
|
||||
<span class="var">self</span>.<span class="attr">titel</span> = <span class="var">titel</span>
|
||||
<span class="var">self</span>.<span class="attr">autor</span> = <span class="var">autor</span>
|
||||
|
||||
<span class="kw">def</span> <span class="fn">__str__</span>(<span class="var">self</span>):
|
||||
<span class="kw">return</span> <span class="str">f"'{self.titel}' von {self.autor}"</span> <span class="cm"># MUSS ein String sein!</span>
|
||||
|
||||
<span class="var">mein_buch</span> = <span class="fn">Buch</span>(<span class="str">"Harry Potter"</span>, <span class="str">"J.K. Rowling"</span>)
|
||||
<span class="fn">print</span>(<span class="var">mein_buch</span>) <span class="cm"># Ausgabe: 'Harry Potter' von J.K. Rowling</span></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Objektlisten Card -->
|
||||
<section class="card">
|
||||
<h2>2. Objekte in Listen verwalten</h2>
|
||||
|
||||
<p>
|
||||
Eine Klasse kann als Attribut eine <strong>Liste von anderen Objekten</strong> haben:
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🛒 Der Warenkorb:</div>
|
||||
Ein <code>Warenkorb</code> besitzt eine Liste <code>self.artikel_liste = []</code>. Wenn du einen <code>Artikel</code> hinzufügst, landet das ganze Artikel-Objekt in der Liste!
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben Card -->
|
||||
<section class="card">
|
||||
<h2>3. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4_1">
|
||||
<label for="t4_1" class="task-label">
|
||||
<strong>TODO 1:</strong> <code>Artikel.__init__(self, name, preis, anzahl=1)</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4_2">
|
||||
<label for="t4_2" class="task-label">
|
||||
<strong>TODO 2:</strong> <code>Artikel.gesamtpreis(self)</code> -> <code>self.preis * self.anzahl</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4_3">
|
||||
<label for="t4_3" class="task-label">
|
||||
<strong>TODO 3:</strong> <code>Artikel.__str__(self)</code> -> z.B. <code>"2x Milch (je 1.29 €) = 2.58 €"</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t4_4">
|
||||
<label for="t4_4" class="task-label">
|
||||
<strong>TODO 4-7:</strong> <code>Warenkorb</code> mit <code>artikel_hinzufuegen</code>, <code>gesamtsumme</code> und <code>bon_text</code>.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zu TODO 7 (Kassenzettel zusammensetzen)</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">bon_text</span>(<span class="var">self</span>):
|
||||
<span class="var">zeilen</span> = [<span class="str">"--- KASSENZETTEL ---"</span>]
|
||||
<span class="kw">for</span> <span class="var">artikel</span> <span class="kw">in</span> <span class="var">self</span>.<span class="attr">artikel_liste</span>:
|
||||
<span class="var">zeilen</span>.<span class="fn">append</span>(<span class="fn">str</span>(<span class="var">artikel</span>)) <span class="cm"># Nutzt automatisch __str__ des Artikels!</span>
|
||||
<span class="var">zeilen</span>.<span class="fn">append</span>(<span class="str">"--------------------"</span>)
|
||||
<span class="var">zeilen</span>.<span class="fn">append</span>(<span class="str">f"Gesamtsumme: {self.gesamtsumme():.2f} €"</span>)
|
||||
<span class="kw">return</span> <span class="str">"\n"</span>.<span class="fn">join</span>(<span class="var">zeilen</span>)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- Testen & Footer Navigation -->
|
||||
<section class="card">
|
||||
<h2>4. Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal im Ordner <code>04_str_und_darstellung</code> 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="../03_methoden_und_verhalten/index.html" class="btn btn-secondary">← Zurück zu Kapitel 03</a>
|
||||
<a href="../05_objekte_kombinieren/index.html" class="btn">Weiter zu Kapitel 05 →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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!")
|
||||
|
|
|
|||
150
05_objekte_kombinieren/index.html
Normal file
150
05_objekte_kombinieren/index.html
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 05: Komposition und Playlists</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="../04_str_und_darstellung/index.html">Kapitel 04</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel 05</span>
|
||||
</nav>
|
||||
<div class="header-badge">Kapitel 05</div>
|
||||
<h1>Komposition: Objekte kombinieren & filtern 🎵</h1>
|
||||
<p>Baue einen eigenen Spotify-Playlist-Manager und lerne, wie Objekte andere Objekte suchen, berechnen und filtern.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Theorie Card -->
|
||||
<section class="card">
|
||||
<h2>1. Was ist Komposition?</h2>
|
||||
|
||||
<p>
|
||||
In großen Anwendungen (wie Spotify, Netflix oder Videospielen) arbeiten viele Klassen zusammen. Wenn eine Klasse Instanzen einer anderen Klasse beinhaltet, nennt man das <strong>Komposition</strong> (oder *"hat-ein"-Beziehung*):
|
||||
</p>
|
||||
|
||||
<ul style="margin-left: 20px; margin-bottom: 15px;">
|
||||
<li>Eine <strong>Playlist</strong> <em>hat</em> viele <strong>Songs</strong>.</li>
|
||||
<li>Ein <strong>Kino</strong> <em>hat</em> viele <strong>Säle</strong> und <strong>Filme</strong>.</li>
|
||||
</ul>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🎧 Die Spotify-Analogie:</div>
|
||||
Ein <code>Song</code> speichert seinen Titel, den Künstler und die Länge in Sekunden. Die <code>Playlist</code> kümmert sich um die Gesamtübersicht: Wie viele Songs gibt es? Wie lange dauert die Playlist insgesamt? Gibt es Lieder von Taylor Swift?
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Filter & Formatierung Card -->
|
||||
<section class="card">
|
||||
<h2>2. Nützliche Python-Kniffe</h2>
|
||||
|
||||
<h3>⏱️ Sekunden in "MM:SS" umrechnen</h3>
|
||||
<p>
|
||||
Mit Ganzzahldivision <code>//</code> und Modulo <code>%</code> rechnen wir Sekunden in Minuten um:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Python</span>
|
||||
</div>
|
||||
<pre><span class="var">gesamt_sekunden</span> = <span class="num">215</span>
|
||||
<span class="var">minuten</span> = <span class="var">gesamt_sekunden</span> // <span class="num">60</span> <span class="cm"># 3 Minuten</span>
|
||||
<span class="var">sekunden</span> = <span class="var">gesamt_sekunden</span> % <span class="num">60</span> <span class="cm"># 35 Restsekunden</span>
|
||||
|
||||
<span class="cm"># :02d sorgt für zweistellige Zahlen mit führender Null (z.B. 03:05 statt 3:5):</span>
|
||||
<span class="var">zeit_text</span> = <span class="str">f"{minuten:02d}:{sekunden:02d}"</span> <span class="cm"># "03:35"</span></pre>
|
||||
</div>
|
||||
|
||||
<h3>🔍 Groß- und Kleinschreibung beim Suchen ignorieren</h3>
|
||||
<p>
|
||||
Damit <code>"Taylor Swift"</code> auch gefunden wird, wenn jemand <code>"taylor swift"</code> eingibt, nutzen wir <code>.lower()</code>:
|
||||
</p>
|
||||
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">if</span> <span class="var">song</span>.<span class="attr">kuenstler</span>.<span class="fn">lower</span>() == <span class="var">gesuchter_kuenstler</span>.<span class="fn">lower</span>():
|
||||
<span class="var">treffer</span>.<span class="fn">append</span>(<span class="var">song</span>)</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben Card -->
|
||||
<section class="card">
|
||||
<h2>3. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5_1">
|
||||
<label for="t5_1" class="task-label">
|
||||
<strong>Klasse Song:</strong> <code>__init__(titel, kuenstler, dauer_sekunden)</code>, <code>formatierte_dauer()</code> ("MM:SS") und <code>__str__()</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5_2">
|
||||
<label for="t5_2" class="task-label">
|
||||
<strong>Klasse Playlist:</strong> <code>__init__(name)</code> mit <code>self.songs = []</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5_3">
|
||||
<label for="t5_3" class="task-label">
|
||||
<strong>Playlist Methoden:</strong> <code>song_hinzufuegen</code>, <code>anzahl_songs</code>, <code>gesamtdauer_sekunden</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t5_4">
|
||||
<label for="t5_4" class="task-label">
|
||||
<strong>Playlist Suchen & Finden:</strong> <code>finde_songs_von(kuenstler)</code> und <code>laengster_song()</code>.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zum längsten Song finden</summary>
|
||||
<div class="details-content">
|
||||
<div class="code-container">
|
||||
<pre><span class="kw">def</span> <span class="fn">laengster_song</span>(<span class="var">self</span>):
|
||||
<span class="kw">if</span> <span class="kw">not</span> <span class="var">self</span>.<span class="attr">songs</span>:
|
||||
<span class="kw">return</span> <span class="kw">None</span>
|
||||
|
||||
<span class="var">bester_song</span> = <span class="var">self</span>.<span class="attr">songs</span>[<span class="num">0</span>]
|
||||
<span class="kw">for</span> <span class="var">s</span> <span class="kw">in</span> <span class="var">self</span>.<span class="attr">songs</span>:
|
||||
<span class="kw">if</span> <span class="var">s</span>.<span class="attr">dauer_sekunden</span> > <span class="var">bester_song</span>.<span class="attr">dauer_sekunden</span>:
|
||||
<span class="var">bester_song</span> = <span class="var">s</span>
|
||||
<span class="kw">return</span> <span class="var">bester_song</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- Testen & Footer Navigation -->
|
||||
<section class="card">
|
||||
<h2>4. Lösung überprüfen</h2>
|
||||
<p>Führe im Terminal im Ordner <code>05_objekte_kombinieren</code> 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="../04_str_und_darstellung/index.html" class="btn btn-secondary">← Zurück zu Kapitel 04</a>
|
||||
<a href="../06_abschlussprojekt_tamagotchi/index.html" class="btn">Weiter zum Abschlussprojekt →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -23,7 +23,7 @@ Du kannst mit ihm interagieren:
|
|||
- 🍎 **Füttern** (`fuettern`): Senkt den Hunger, macht etwas müde und etwas glücklicher.
|
||||
- ⚽ **Spielen** (`spielen`): Steigert das Glück, macht aber hungrig und müde. Zu müde Haustiere weigern sich zu spielen!
|
||||
- 💤 **Schlafen** (`schlafen`): Setzt die Müdigkeit auf 0, lässt einen Tag vergehen (`alter_tage += 1`), macht aber etwas hungrig.
|
||||
- ⏳ **Zeit vergeht** (`zeit_vergeht`): Das Haustier wird hungriger, müder und etwas trauriger. Wenn der Hunger 100 erreicht, schläft es für immer ein...
|
||||
- ⏳ **Zeit vergeht** (`zeit_vergeht`): Das Haustier wird hungriger, müder und etwas trauriger. Wenn der Hunger 100 erreicht oder Glück 0 wird, schläft es für immer ein...
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class Tamagotchi:
|
|||
# ==========================================================================
|
||||
# TODO 1: Konstruktor __init__(self, name, tierart="Drache")
|
||||
#
|
||||
# Initialisiere die folgenden Attribute:
|
||||
# Initialisiere die folgenden Attribute an self:
|
||||
# - self.name = name
|
||||
# - self.tierart = tierart
|
||||
# - self.hunger = 50 (0 = pappsatt, 100 = verhungert)
|
||||
|
|
@ -22,10 +22,9 @@ class Tamagotchi:
|
|||
# Schreibe hier deinen Code für TODO 1:
|
||||
pass
|
||||
|
||||
# Hilfsmethode (optional, aber sehr nützlich):
|
||||
# Hält einen Wert zwischen minimal 0 und maximal 100.
|
||||
def _begrenze(self, wert):
|
||||
return max(0, min(100, wert))
|
||||
# Hilfsmethode: Begrenzt Werte immer zwischen min_wert (0) und max_wert (100)
|
||||
def _begrenze(self, wert, min_wert=0, max_wert=100):
|
||||
return max(min_wert, min(max_wert, wert))
|
||||
|
||||
# ==========================================================================
|
||||
# TODO 2: Methode "fuettern(self, menge=20)"
|
||||
|
|
@ -34,9 +33,9 @@ class Tamagotchi:
|
|||
# 1. Wenn not self.ist_lebendig:
|
||||
# - Gib zurück: f"{self.name} reagiert nicht mehr..."
|
||||
# 2. Wenn lebendig:
|
||||
# - Verringere 'self.hunger' um 'menge' (darf nicht unter 0 fallen).
|
||||
# - Erhöhe 'self.glueck' um 5 (darf nicht über 100 steigen).
|
||||
# - Erhöhe 'self.muedigkeit' um 5 (darf nicht über 100 steigen).
|
||||
# - Verringere self.hunger um menge (mit _begrenze, darf nicht unter 0 fallen).
|
||||
# - Erhöhe self.glueck um 5 (max 100).
|
||||
# - Erhöhe self.muedigkeit um 5 (max 100).
|
||||
# - Gib zurück: f"{self.name} mampft genüsslich! (Hunger: {self.hunger}/100)"
|
||||
# ==========================================================================
|
||||
def fuettern(self, menge=20):
|
||||
|
|
@ -49,13 +48,13 @@ class Tamagotchi:
|
|||
# Regeln:
|
||||
# 1. Wenn not self.ist_lebendig:
|
||||
# - Gib zurück: f"{self.name} reagiert nicht mehr..."
|
||||
# 2. Wenn 'self.muedigkeit' > 80 ist:
|
||||
# 2. Wenn self.muedigkeit > 80 ist:
|
||||
# - Zu müde zum Spielen! Ändere keine Werte und gib zurück:
|
||||
# f"{self.name} ist zu müde zum Spielen und gähnt nur..."
|
||||
# 3. Wenn fit genug:
|
||||
# - Erhöhe 'self.glueck' um 'spass' (max 100).
|
||||
# - Erhöhe 'self.hunger' um 15 (max 100).
|
||||
# - Erhöhe 'self.muedigkeit' um 20 (max 100).
|
||||
# - Erhöhe self.glueck um spass (max 100).
|
||||
# - Erhöhe self.hunger um 15 (max 100).
|
||||
# - Erhöhe self.muedigkeit um 20 (max 100).
|
||||
# - Gib zurück: f"{self.name} hatte riesigen Spaß beim Spielen! (Glück: {self.glueck}/100)"
|
||||
# ==========================================================================
|
||||
def spielen(self, spass=25):
|
||||
|
|
@ -69,9 +68,9 @@ class Tamagotchi:
|
|||
# 1. Wenn not self.ist_lebendig:
|
||||
# - Gib zurück: f"{self.name} reagiert nicht mehr..."
|
||||
# 2. Wenn lebendig:
|
||||
# - Setze 'self.muedigkeit' auf 0.
|
||||
# - Erhöhe 'self.hunger' um 15 (max 100).
|
||||
# - Erhöhe 'self.alter_tage' um 1.
|
||||
# - Setze self.muedigkeit auf 0.
|
||||
# - Erhöhe self.hunger um 15 (max 100).
|
||||
# - Erhöhe self.alter_tage um 1.
|
||||
# - Gib zurück: f"{self.name} hat tief geschlafen und ist ausgeruht! Ein neuer Tag bricht an."
|
||||
# ==========================================================================
|
||||
def schlafen(self):
|
||||
|
|
@ -86,9 +85,9 @@ class Tamagotchi:
|
|||
# 1. Wenn not self.ist_lebendig:
|
||||
# - Mach nichts, gib False zurück.
|
||||
# 2. Wenn lebendig:
|
||||
# - Erhöhe 'self.hunger' um 10 (max 100).
|
||||
# - Erhöhe 'self.muedigkeit' um 10 (max 100).
|
||||
# - Verringere 'self.glueck' um 10 (min 0).
|
||||
# - Erhöhe self.hunger um 10 (max 100).
|
||||
# - Erhöhe self.muedigkeit um 10 (max 100).
|
||||
# - Verringere self.glueck um 10 (min 0).
|
||||
# - Prüfe, ob das Haustier stirbt:
|
||||
# Wenn self.hunger >= 100 oder self.glueck <= 0:
|
||||
# self.ist_lebendig = False
|
||||
|
|
@ -118,12 +117,16 @@ class Tamagotchi:
|
|||
|
||||
# ==============================================================================
|
||||
# Schneller Testlauf:
|
||||
# (Ausführen mit 'python3 aufgabe.py' oder starte 'python3 tamagotchi_spiel.py')
|
||||
# ==============================================================================
|
||||
if __name__ == "__main__":
|
||||
pet = Tamagotchi("Yoshi", "Dino")
|
||||
print(pet)
|
||||
print()
|
||||
print(pet.fuettern())
|
||||
print(pet.spielen())
|
||||
print(pet.schlafen())
|
||||
print(pet)
|
||||
if hasattr(pet, "name") and pet.name:
|
||||
print(pet)
|
||||
print()
|
||||
print(pet.fuettern())
|
||||
print(pet.spielen())
|
||||
print(pet.schlafen())
|
||||
print(pet)
|
||||
else:
|
||||
print("💡 Hinweis: Implementiere erst die TODOs, um Yoshi zum Leben zu erwecken!")
|
||||
|
|
|
|||
133
06_abschlussprojekt_tamagotchi/index.html
Normal file
133
06_abschlussprojekt_tamagotchi/index.html
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kapitel 06: Tamagotchi Abschlussprojekt</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="../05_objekte_kombinieren/index.html">Kapitel 05</a>
|
||||
<span>›</span>
|
||||
<span style="color: white; font-weight: 600;">Kapitel 06</span>
|
||||
</nav>
|
||||
<div class="header-badge">Abschlussprojekt</div>
|
||||
<h1>Dein eigenes Tamagotchi (Virtuelles Haustier) 🥚🐣</h1>
|
||||
<p>Kombiniere alle Konzepte in einem interaktiven, voll funktionsfähigen Konsolenspiel!</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Übersicht Card -->
|
||||
<section class="card">
|
||||
<h2>1. Das große Finale! 🏆</h2>
|
||||
|
||||
<p>
|
||||
Du hast alle Grundlagen gelernt: Klassen definieren, <code>__init__</code> & <code>self</code> nutzen, Methoden schreiben, <code>__str__</code> gestalten und Objekte verwalten.
|
||||
</p>
|
||||
<p>
|
||||
Jetzt bauen wir ein komplettes, lebendiges <strong>Tamagotchi</strong>, das du im Terminal füttern, schlafen legen und mit dem du spielen kannst!
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🎮 Wie das Spiel funktioniert:</div>
|
||||
<ul style="margin-left: 20px;">
|
||||
<li>🍖 <strong>Hunger</strong> (0 bis 100): Steigt mit der Zeit, sinkt beim Füttern. Bei 100 stirbt das Haustier!</li>
|
||||
<li>💤 <strong>Müdigkeit</strong> (0 bis 100): Steigt bei Aktionen. Bei über 80 weigert es sich zu spielen. Schlafen setzt Müdigkeit auf 0.</li>
|
||||
<li>💖 <strong>Glück</strong> (0 bis 100): Steigt beim Spielen, sinkt mit der Zeit. Bei 0 stirbt das Haustier vor Einsamkeit.</li>
|
||||
<li>📅 <strong>Alter</strong>: Bei jedem Schlafen vergeht ein neuer Tag (<code>alter_tage += 1</code>).</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aufgaben Card -->
|
||||
<section class="card">
|
||||
<h2>2. Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||||
|
||||
<ul class="task-list">
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_1">
|
||||
<label for="t6_1" class="task-label">
|
||||
<strong>TODO 1:</strong> Konstruktor <code>__init__(self, name, tierart="Drache")</code>: Startwerte <code>hunger=50</code>, <code>muedigkeit=20</code>, <code>glueck=80</code>, <code>alter_tage=0</code>, <code>ist_lebendig=True</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_2">
|
||||
<label for="t6_2" class="task-label">
|
||||
<strong>TODO 2:</strong> Methode <code>fuettern(self, menge=20)</code>: Senkt Hunger, erhöht Glück & Müdigkeit um 5.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_3">
|
||||
<label for="t6_3" class="task-label">
|
||||
<strong>TODO 3:</strong> Methode <code>spielen(self, spass=25)</code>: Steigert Glück, erhöht Hunger (15) & Müdigkeit (20). Wenn <code>muedigkeit > 80</code> -> ablehnen!
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_4">
|
||||
<label for="t6_4" class="task-label">
|
||||
<strong>TODO 4:</strong> Methode <code>schlafen(self)</code>: Müdigkeit auf 0, Hunger +15, <code>alter_tage += 1</code>.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_5">
|
||||
<label for="t6_5" class="task-label">
|
||||
<strong>TODO 5:</strong> Methode <code>zeit_vergeht(self)</code>: Hunger +10, Müdigkeit +10, Glück -10. Prüfen, ob Hunger >= 100 oder Glück <= 0.
|
||||
</label>
|
||||
</li>
|
||||
<li class="task-item">
|
||||
<input type="checkbox" class="task-checkbox" id="t6_6">
|
||||
<label for="t6_6" class="task-label">
|
||||
<strong>TODO 6:</strong> Dunder-Methode <code>__str__(self)</code>: Statusanzeige mit Name, Tierart, Alter und Werten.
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||
|
||||
<details>
|
||||
<summary>Tipp zur Werte-Begrenzung (Clamping)</summary>
|
||||
<div class="details-content">
|
||||
<p>Damit Werte nicht negativ werden oder 100 überschreiten, kannst du die Hilfsfunktion <code>max(0, min(100, wert))</code> nutzen:</p>
|
||||
<div class="code-container">
|
||||
<pre><span class="var">self</span>.<span class="attr">hunger</span> = <span class="fn">max</span>(<span class="num">0</span>, <span class="fn">min</span>(<span class="num">100</span>, <span class="var">self</span>.<span class="attr">hunger</span> - <span class="var">menge</span>))</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- Spiel starten Card -->
|
||||
<section class="card">
|
||||
<h2>3. Das interaktive Spiel starten! 🕹️</h2>
|
||||
|
||||
<p>Sobald deine Tests grün sind, kannst du das Spiel live spielen:</p>
|
||||
|
||||
<div class="code-container">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 tamagotchi_spiel.py</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="box box-success">
|
||||
<div class="box-title">🎉 Geschafft!</div>
|
||||
Du hast damit erfolgreich gelernt, wie man objektorientiert in Python programmiert!
|
||||
</div>
|
||||
|
||||
<div class="footer-nav">
|
||||
<a href="../05_objekte_kombinieren/index.html" class="btn btn-secondary">← Zurück zu Kapitel 05</a>
|
||||
<a href="../index.html" class="btn">Zurück zur Hauptübersicht 🏠</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
449
assets/style.css
Normal file
449
assets/style.css
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
/* ==========================================================================
|
||||
Modernes Design-System für Python OOP Lernportal
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
--primary: #6366f1;
|
||||
--primary-hover: #4f46e5;
|
||||
--primary-light: #eef2ff;
|
||||
--secondary: #06b6d4;
|
||||
--success: #10b981;
|
||||
--success-light: #ecfdf5;
|
||||
--warning: #f59e0b;
|
||||
--warning-light: #fffbeb;
|
||||
--danger: #ef4444;
|
||||
--danger-light: #fef2f2;
|
||||
--purple: #8b5cf6;
|
||||
--purple-light: #f5f3ff;
|
||||
|
||||
--bg-main: #f8fafc;
|
||||
--bg-card: #ffffff;
|
||||
--bg-code: #1e293b;
|
||||
--border-color: #e2e8f0;
|
||||
--text-main: #1e293b;
|
||||
--text-muted: #64748b;
|
||||
--text-code: #f1f5f9;
|
||||
|
||||
--radius-sm: 6px;
|
||||
--radius-md: 12px;
|
||||
--radius-lg: 18px;
|
||||
--shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.08), 0 2px 4px -1px rgba(0,0,0,0.04);
|
||||
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -2px rgba(0,0,0,0.04);
|
||||
--font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
--font-mono: 'Fira Code', 'JetBrains Mono', Consolas, Monaco, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
background-color: var(--bg-main);
|
||||
color: var(--text-main);
|
||||
line-height: 1.65;
|
||||
font-size: 16px;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* Header & Navigation */
|
||||
header {
|
||||
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
||||
color: white;
|
||||
padding: 30px 20px;
|
||||
box-shadow: var(--shadow-md);
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 0.9rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-decoration: none;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
transition: all 0.2s;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
color: white;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.header-badge {
|
||||
display: inline-block;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 2.1rem;
|
||||
font-weight: 800;
|
||||
margin-bottom: 6px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
header p {
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Main Container */
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* Content Cards */
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 28px;
|
||||
margin-bottom: 25px;
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 1.45rem;
|
||||
color: var(--primary);
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-bottom: 2px solid var(--primary-light);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 1.2rem;
|
||||
margin: 20px 0 10px 0;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
/* Didactic Callout Boxes */
|
||||
.box {
|
||||
border-radius: var(--radius-md);
|
||||
padding: 18px 22px;
|
||||
margin: 20px 0;
|
||||
border-left: 5px solid;
|
||||
}
|
||||
|
||||
.box-title {
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.box-analogie {
|
||||
background-color: var(--purple-light);
|
||||
border-left-color: var(--purple);
|
||||
color: #4c1d95;
|
||||
}
|
||||
|
||||
.box-tipp {
|
||||
background-color: var(--primary-light);
|
||||
border-left-color: var(--primary);
|
||||
color: #312e81;
|
||||
}
|
||||
|
||||
.box-warning {
|
||||
background-color: var(--warning-light);
|
||||
border-left-color: var(--warning);
|
||||
color: #78350f;
|
||||
}
|
||||
|
||||
.box-danger {
|
||||
background-color: var(--danger-light);
|
||||
border-left-color: var(--danger);
|
||||
color: #7f1d1d;
|
||||
}
|
||||
|
||||
.box-success {
|
||||
background-color: var(--success-light);
|
||||
border-left-color: var(--success);
|
||||
color: #064e3b;
|
||||
}
|
||||
|
||||
/* Code Blocks */
|
||||
.code-container {
|
||||
background-color: var(--bg-code);
|
||||
border-radius: var(--radius-md);
|
||||
margin: 18px 0;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.code-header {
|
||||
background-color: #0f172a;
|
||||
color: #94a3b8;
|
||||
padding: 8px 16px;
|
||||
font-size: 0.8rem;
|
||||
font-family: var(--font-mono);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.code-dots {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.code-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.dot-red { background-color: #ef4444; }
|
||||
.dot-yellow { background-color: #f59e0b; }
|
||||
.dot-green { background-color: #10b981; }
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.92rem;
|
||||
color: var(--text-code);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
background-color: #f1f5f9;
|
||||
color: #e11d48;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Code Syntax Highlights (CSS simulated) */
|
||||
.kw { color: #f472b6; font-weight: bold; } /* def, class, return, if */
|
||||
.fn { color: #60a5fa; } /* function name */
|
||||
.str { color: #a7f3d0; } /* strings */
|
||||
.num { color: #fbbf24; } /* numbers */
|
||||
.cm { color: #64748b; font-style: italic; } /* comments */
|
||||
.var { color: #cbd5e1; } /* self, variables */
|
||||
.attr { color: #38bdf8; } /* self.attributes */
|
||||
|
||||
/* Accordion / Details */
|
||||
details {
|
||||
background: #f8fafc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 12px 16px;
|
||||
margin: 12px 0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
details[open] {
|
||||
background: #ffffff;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
summary {
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
color: var(--primary);
|
||||
user-select: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
summary:hover {
|
||||
color: var(--primary-hover);
|
||||
}
|
||||
|
||||
.details-content {
|
||||
margin-top: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* Checklists & Tasks */
|
||||
.task-list {
|
||||
list-style: none;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 10px 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
margin-bottom: 8px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
background: var(--primary-light);
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 3px;
|
||||
accent-color: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.task-label {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Grid & Roadmap Cards (for Overview) */
|
||||
.roadmap-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.roadmap-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 20px;
|
||||
text-decoration: none;
|
||||
color: var(--text-main);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.roadmap-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.roadmap-number {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
color: var(--primary);
|
||||
background: var(--primary-light);
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 10px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.roadmap-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.roadmap-desc {
|
||||
font-size: 0.92rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 14px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.roadmap-footer {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* Buttons & Links */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 18px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
border-radius: var(--radius-sm);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: var(--primary-hover);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #f1f5f9;
|
||||
color: var(--text-main);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #e2e8f0;
|
||||
}
|
||||
|
||||
.footer-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 35px;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 600px) {
|
||||
header h1 { font-size: 1.6rem; }
|
||||
.card { padding: 18px; }
|
||||
.footer-nav { flex-direction: column; }
|
||||
.footer-nav .btn { width: 100%; justify-content: center; }
|
||||
}
|
||||
166
index.html
Normal file
166
index.html
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Python OOP Lernportal: Klassen & Objekte</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</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 komplexe Programme strukturierst.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
|
||||
<!-- Willkommen Card -->
|
||||
<section class="card">
|
||||
<h2>👋 Willkommen zu deiner Übungsreihe!</h2>
|
||||
<p>
|
||||
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: <strong>Klassen & Objekte</strong>!
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<div class="box box-analogie">
|
||||
<div class="box-title">🏗️ Die Grundidee 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>
|
||||
</section>
|
||||
|
||||
<!-- Roadmap Grid -->
|
||||
<section>
|
||||
<h2 style="margin: 30px 0 15px 0; color: var(--text-main); font-size: 1.5rem;">🗺️ Dein Lernpfad (Kapitel 01 bis 06)</h2>
|
||||
<div class="roadmap-grid">
|
||||
|
||||
<!-- Kapitel 1 -->
|
||||
<a href="01_einstieg_klassen/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 01</span>
|
||||
<div class="roadmap-title">🐶 Die erste Klasse</div>
|
||||
<div class="roadmap-desc">Was ist eine Klasse? Bauplan vs. Objekt, Instanziierung und erste Attribute am Haustier-Beispiel.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 2 -->
|
||||
<a href="02_init_und_self/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 02</span>
|
||||
<div class="roadmap-title">💳 Konstruktor & self</div>
|
||||
<div class="roadmap-desc">Wie <code>__init__</code> Objekte startklar macht und was das Wörtchen <code>self</code> wirklich bedeutet (Bankkonto-App).</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 3 -->
|
||||
<a href="03_methoden_und_verhalten/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 03</span>
|
||||
<div class="roadmap-title">⚔️ Methoden & Verhalten</div>
|
||||
<div class="roadmap-desc">Objekte führen Aktionen aus! Interaktion zwischen Helden und Monstern in einem RPG-Kampfsimulator.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 4 -->
|
||||
<a href="04_str_und_darstellung/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 04</span>
|
||||
<div class="roadmap-title">🧾 Schöne Textausgabe</div>
|
||||
<div class="roadmap-desc">Wie man <code>print(objekt)</code> mit <code>__str__</code> lesbar macht und Objekte im Warenkorb sammelt.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 5 -->
|
||||
<a href="05_objekte_kombinieren/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 05</span>
|
||||
<div class="roadmap-title">🎵 Komposition & Playlists</div>
|
||||
<div class="roadmap-desc">Objekte verwalten andere Objekte: Song-Suche, Längenberechnung und Filter in Spotify-Playlists.</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
<!-- Kapitel 6 -->
|
||||
<a href="06_abschlussprojekt_tamagotchi/index.html" class="roadmap-card">
|
||||
<div>
|
||||
<span class="roadmap-number">Kapitel 06</span>
|
||||
<div class="roadmap-title">🥚 Tamagotchi Mini-Projekt</div>
|
||||
<div class="roadmap-desc">Kombiniere alles in einem voll spielbaren, interaktiven virtuellen Haustier für dein Terminal!</div>
|
||||
</div>
|
||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Wie lerne ich Card -->
|
||||
<section class="card">
|
||||
<h2>🚀 Wie du vorgehst (Schritt-für-Schritt)</h2>
|
||||
<ol style="margin-left: 20px; margin-bottom: 15px;">
|
||||
<li style="margin-bottom: 8px;">Wähle das nächste offene Kapitel aus der Liste oben.</li>
|
||||
<li style="margin-bottom: 8px;">Lies die Erklärungen und schau dir die Codebeispiele und „Stolperfallen“ an.</li>
|
||||
<li style="margin-bottom: 8px;">Öffne die <code>aufgabe.py</code> im entsprechenden Kapitelordner und löse die <code>TODO</code>s.</li>
|
||||
<li style="margin-bottom: 8px;">
|
||||
Führe im Terminal den automatischen Test aus:
|
||||
<div class="code-container" style="margin: 10px 0;">
|
||||
<div class="code-header">
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>Wenn alle Tests mit <strong>OK</strong> durchlaufen, hast du das Kapitel erfolgreich gemeistert! 🎉</li>
|
||||
</ol>
|
||||
|
||||
<div class="box box-tipp">
|
||||
<div class="box-title">💡 Gesamten Fortschritt auf einen Blick prüfen:</div>
|
||||
Du kannst jederzeit im Hauptordner folgenden Befehl ausführen, um zu sehen, wie viele Kapitel du schon gelöst hast:
|
||||
<div class="code-container" style="margin: 8px 0 0 0;">
|
||||
<pre><code>python3 test_all.py</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ & Troubleshooting Card -->
|
||||
<section class="card">
|
||||
<h2>🩺 Erste Hilfe & Häufige Fragen</h2>
|
||||
|
||||
<details>
|
||||
<summary>❌ Fehlermeldung: <code>TypeError: ... takes 0 positional arguments but 1 was given</code></summary>
|
||||
<div class="details-content">
|
||||
<p><strong>Ursache:</strong> Du hast bei einer Methode in deiner Klasse das <code>self</code> im Methodenkopf vergessen!</p>
|
||||
<p><strong>Lösung:</strong> Schreibe <code>def meine_methode(self):</code> statt <code>def meine_methode():</code>. Python übergibt bei Methodenaufrufen immer automatisch das Objekt selbst als erstes Argument.</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>❌ Fehlermeldung: <code>AttributeError: 'NoneType' object has no attribute '...'</code></summary>
|
||||
<div class="details-content">
|
||||
<p><strong>Ursache:</strong> Eine Funktion oder Methode hat nichts zurückgegeben (also <code>None</code>), und du versuchst, auf ein Attribut davon zuzugreifen.</p>
|
||||
<p><strong>Lösung:</strong> Prüfe, ob du am Ende der Funktion das <code>return objekt</code> vergessen hast!</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>❌ Der Test schlägt fehl, obwohl ich die richtige Ausgabe in der Konsole sehe?</summary>
|
||||
<div class="details-content">
|
||||
<p><strong>Ursache:</strong> Du hast vermutlich <code>print(...)</code> verwendet, anstatt den Wert mit <code>return ...</code> zurückzugeben.</p>
|
||||
<p><strong>Lösung:</strong> Die automatischen Tests prüfen den Rückgabewert (<code>return</code>) deiner Funktionen/Methoden, nicht das, was auf dem Bildschirm ausgegeben wird.</p>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue