Füge Vorkapitel 00 zur Fehlersuche und Python-Debugging (Bug-Hunt Detektiv-Aufgabe) hinzu
This commit is contained in:
parent
35f57ac484
commit
b0e53d3e09
9 changed files with 490 additions and 38 deletions
53
00_fehlersuche_und_grundlagen/README.md
Normal file
53
00_fehlersuche_und_grundlagen/README.md
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Vorkapitel 00: Python Fehlersuche & Grundlagen 🔍🕵️♀️
|
||||||
|
|
||||||
|
Herzlich willkommen zum Warm-up!
|
||||||
|
|
||||||
|
Bevor wir mit Klassen und objektorientierter Programmierung starten, lernen wir das wichtigste Handwerkszeug jeder guten Entwicklerin: **Wie man Fehler im Code schnell findet und behebt.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Fehlermeldungen richtig lesen: Die Unten-nach-Oben-Regel
|
||||||
|
|
||||||
|
Wenn Python stoppt und einen roten Text anzeigt, nennt man das einen **Traceback**.
|
||||||
|
Lies immer ganz unten:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "aufgabe.py", line 15, in <module>
|
||||||
|
summe = punkte + bonus
|
||||||
|
TypeError: unsupported operand type(s) for +: 'int' and 'str'
|
||||||
|
```
|
||||||
|
1. **Ganz unten:** Was ist das Problem? (`TypeError: ... 'int' and 'str'`)
|
||||||
|
2. **Zeile darüber:** Wo ist es passiert? (`line 15`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚫 Die 4 häufigsten Python-Fehler
|
||||||
|
|
||||||
|
1. **`IndentationError`:**
|
||||||
|
In Python müssen Codeblöcke in Funktionen, Bedingungen und Schleifen **genau 4 Leerzeichen** eingerückt sein.
|
||||||
|
2. **`SyntaxError`:**
|
||||||
|
Doppelpunkte am Ende von `def`, `if`, `else`, `for` vergessen oder ungeschlossene Klammern `)`.
|
||||||
|
3. **`NameError`:**
|
||||||
|
Tippfehler beim Namen einer Variable oder Funktion (z.B. `spielr_name` statt `spieler_name`).
|
||||||
|
4. **`TypeError`:**
|
||||||
|
Falsche Datentypen gemischt (z.B. `"Ergebnis: " + 10` statt `f"Ergebnis: {10}"`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Deine Detektiv-Aufgabe in `aufgabe.py`
|
||||||
|
|
||||||
|
In `aufgabe.py` hat sich ein fehlerhaftes Quiz-Programm eingeschlichen. Deine Aufgabe ist es, die 5 versteckten Fehler zu finden und zu reparieren.
|
||||||
|
|
||||||
|
### Vorgehen:
|
||||||
|
1. Führe die Datei im Terminal aus:
|
||||||
|
```bash
|
||||||
|
python3 aufgabe.py
|
||||||
|
```
|
||||||
|
2. Lies die Fehlermeldung von unten nach oben.
|
||||||
|
3. Behebe den ersten angezeigten Fehler.
|
||||||
|
4. Wiederhole die Schritte, bis das Skript ohne Fehler durchläuft!
|
||||||
|
5. Führe den Test zur Bestätigung aus:
|
||||||
|
```bash
|
||||||
|
python3 test_aufgabe.py
|
||||||
|
```
|
||||||
76
00_fehlersuche_und_grundlagen/aufgabe.py
Normal file
76
00_fehlersuche_und_grundlagen/aufgabe.py
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
"""
|
||||||
|
Vorkapitel 00: Python-Detektivin – Finde die 5 versteckten Fehler!
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
In diesem Skript haben sich 5 typische Python-Fehler eingeschlichen.
|
||||||
|
Führe das Skript mit 'python3 aufgabe.py' aus, lies die Fehlermeldungen
|
||||||
|
und behebe die Fehler der Reihe nach von BUG 1 bis BUG 5.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# BUG 1 & BUG 2: SyntaxError & IndentationError
|
||||||
|
# In dieser Funktion fehlen ein Doppelpunkt ':' und die Einrückung stimmt nicht!
|
||||||
|
# ==============================================================================
|
||||||
|
def berechne_endstand(basis_punkte, bonus)
|
||||||
|
gesamt = basis_punkte + bonus
|
||||||
|
if bonus > 10:
|
||||||
|
gesamt += 5 # Hier ist ein Einrückungsfehler!
|
||||||
|
return gesamt
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# BUG 3: NameError
|
||||||
|
# Hier hat sich ein Tippfehler bei einem Variablennamen eingeschlichen!
|
||||||
|
# ==============================================================================
|
||||||
|
def punkte_multiplizieren(spieler_punkte, faktor):
|
||||||
|
# Finde den Tippfehler im Variablennamen:
|
||||||
|
ergebnis = spiler_punkte * faktor
|
||||||
|
return ergebnis
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# BUG 4: TypeError
|
||||||
|
# Hier wird versucht, eine Zahl und einen Text mit '+' zusammenzufügen.
|
||||||
|
# Tipp: Nutze stattdessen einen sauberen f-String: f"Spieler {name} hat {punkte} Punkte!"
|
||||||
|
# ==============================================================================
|
||||||
|
def formatierte_ausgabe(name, punkte):
|
||||||
|
text = "Spieler " + name + " hat " + punkte + " Punkte!"
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# BUG 5: Logik-Fehler (Vergleichsoperator)
|
||||||
|
# Diese Funktion soll True zurückgeben, wenn ein Spieler 50 ODER MEHR Punkte hat.
|
||||||
|
# Aktuell gibt sie bei genau 50 Punkten leider False zurück!
|
||||||
|
# ==============================================================================
|
||||||
|
def ist_sieger(punkte):
|
||||||
|
if punkte > 50:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Hauptprogramm zum Ausprobieren:
|
||||||
|
# (Führe dieses Skript aus mit: python3 aufgabe.py)
|
||||||
|
# ==============================================================================
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🕵️♀️ --- CODE-DETEKTIVIN QUIZ TEST --- 🕵️♀️")
|
||||||
|
|
||||||
|
# Test 1
|
||||||
|
endstand = berechne_endstand(20, 15)
|
||||||
|
print(f"Endstand (sollte 40 sein): {endstand}")
|
||||||
|
|
||||||
|
# Test 2
|
||||||
|
multipliziert = punkte_multiplizieren(10, 3)
|
||||||
|
print(f"Multipliziert (sollte 30 sein): {multipliziert}")
|
||||||
|
|
||||||
|
# Test 3
|
||||||
|
ausgabe = formatierte_ausgabe("Mia", 50)
|
||||||
|
print(f"Formatierte Ausgabe: {ausgabe}")
|
||||||
|
|
||||||
|
# Test 4
|
||||||
|
sieger = ist_sieger(50)
|
||||||
|
print(f"Ist 50 Punkte ein Sieg? (sollte True sein): {sieger}")
|
||||||
|
|
||||||
|
print("\n🎉 Herzlichen Glückwunsch! Alle 5 Bugs wurden erfolgreich behoben!")
|
||||||
209
00_fehlersuche_und_grundlagen/index.html
Normal file
209
00_fehlersuche_und_grundlagen/index.html
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Kapitel 00: Fehlersuche & Grundlagen</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 00</span>
|
||||||
|
<span>›</span>
|
||||||
|
<a href="../01_einstieg_klassen/index.html">Kapitel 01 →</a>
|
||||||
|
</nav>
|
||||||
|
<div class="header-badge">Vorkapitel 00</div>
|
||||||
|
<h1>Python Fehlersuche & Grundlagen 🔍🕵️♀️</h1>
|
||||||
|
<p>Lerne, wie du Fehlermeldungen richtig liest, Einrückungsfehler behebst und Bugs wie eine echte Detektivin aufspürst.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
|
||||||
|
<!-- 1. Keine Panik vor Fehlermeldungen -->
|
||||||
|
<section class="card">
|
||||||
|
<h2>1. Die wichtigste Regel: Keine Panik bei Fehlern!</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Jeder Programmierer auf der Welt – selbst bei Google oder Apple – schreibt täglich dutzende Fehler.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="box box-analogie">
|
||||||
|
<div class="box-title">💡 Der Computer ist dein Assistent, kein Richter:</div>
|
||||||
|
Wenn Python eine rote Fehlermeldung (einen sogenannten <strong>Traceback</strong>) anzeigt, ist das nichts Schlimmes. Der Computer sagt dir damit nur: <em>"Hey, hier verstehe ich in Zeile X etwas noch nicht ganz – kannst du mir kurz helfen?"</em>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Wie liest man einen Traceback? (Die Unten-nach-Oben-Regel)</h3>
|
||||||
|
<p>
|
||||||
|
Ein Traceback kann lang und einschüchternd wirken. Doch das Geheimnis ist: <strong>Lies immer ganz unten!</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code-container">
|
||||||
|
<div class="code-header">
|
||||||
|
<span>Beispiel einer Fehlermeldung</span>
|
||||||
|
</div>
|
||||||
|
<pre>Traceback (most recent call last):
|
||||||
|
File "aufgabe.py", line 12, in berechne_rabatt
|
||||||
|
ergebnis = preis * rabatt_prozent
|
||||||
|
<span class="kw" style="color: #ef4444;">TypeError</span>: can't multiply sequence by non-int of type 'float'
|
||||||
|
<span class="cm">▲ ▲</span>
|
||||||
|
<span class="cm">1. ART DES FEHLERS 2. DIE ERKLÄRUNG</span></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Ganz unten steht:
|
||||||
|
<br>1. <strong>Um welchen Fehler handelt es sich?</strong> (z.B. <code>TypeError</code>)
|
||||||
|
<br>2. <strong>Was genau ist schiefgelaufen?</strong> (z.B. Text mit Kommazahl multipliziert)
|
||||||
|
<br>3. Direkt in der Zeile darüber steht die <strong>Dateiname und Zeilennummer</strong> (z.B. <code>line 12</code>)!
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 2. Die 4 häufigsten Anfängerfehler -->
|
||||||
|
<section class="card">
|
||||||
|
<h2>2. Die 4 häufigsten Python-Fehler im Überblick</h2>
|
||||||
|
|
||||||
|
<!-- Fehler 1: Indentation -->
|
||||||
|
<div class="box box-warning">
|
||||||
|
<div class="box-title">1. IndentationError (Einrückungsfehler)</div>
|
||||||
|
<p>In Python haben Einrückungen eine feste Bedeutung. Alles, was in einer Funktion, Schleife oder Bedingung steht, muss <strong>genau 4 Leerzeichen</strong> eingerückt sein.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="code-container">
|
||||||
|
<div class="code-header"><span>Vergleich: Einrückung</span></div>
|
||||||
|
<pre><span class="cm"># ❌ Falsch:</span>
|
||||||
|
<span class="kw">def</span> <span class="fn">begruessung</span>(<span class="var">name</span>):
|
||||||
|
<span class="fn">print</span>(<span class="str">"Hallo"</span>, <span class="var">name</span>) <span class="cm"># 💥 IndentationError: expected an indented block</span>
|
||||||
|
|
||||||
|
<span class="cm"># ✅ Richtig:</span>
|
||||||
|
<span class="kw">def</span> <span class="fn">begruessung</span>(<span class="var">name</span>):
|
||||||
|
<span class="fn">print</span>(<span class="str">"Hallo"</span>, <span class="var">name</span>) <span class="cm"># 4 Leerzeichen eingerückt!</span></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fehler 2: SyntaxError -->
|
||||||
|
<div class="box box-warning">
|
||||||
|
<div class="box-title">2. SyntaxError (Tippfehler & fehlende Doppelpunkte)</div>
|
||||||
|
<p>Häufig vergessen: Der Doppelpunkt <code>:</code> am Ende von <code>def</code>, <code>if</code>, <code>else</code>, <code>for</code> oder <code>while</code>, oder eine ungeschlossene Klammer.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="code-container">
|
||||||
|
<div class="code-header"><span>Vergleich: Syntax</span></div>
|
||||||
|
<pre><span class="cm"># ❌ Falsch: Doppelpunkt vergessen</span>
|
||||||
|
<span class="kw">if</span> <span class="var">alter</span> >= <span class="num">18</span>
|
||||||
|
<span class="fn">print</span>(<span class="str">"Volljährig"</span>) <span class="cm"># 💥 SyntaxError: expected ':'</span>
|
||||||
|
|
||||||
|
<span class="cm"># ✅ Richtig:</span>
|
||||||
|
<span class="kw">if</span> <span class="var">alter</span> >= <span class="num">18</span>:
|
||||||
|
<span class="fn">print</span>(<span class="str">"Volljährig"</span>)</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fehler 3: NameError -->
|
||||||
|
<div class="box box-warning">
|
||||||
|
<div class="box-title">3. NameError (Unbekannter Name / Tippfehler)</div>
|
||||||
|
<p>Tritt auf, wenn eine Variable oder Funktion aufgerufen wird, die nicht existiert (oder falsch geschrieben wurde).</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="code-container">
|
||||||
|
<div class="code-header"><span>Vergleich: NameError</span></div>
|
||||||
|
<pre><span class="var">spieler_name</span> = <span class="str">"Alex"</span>
|
||||||
|
<span class="fn">print</span>(<span class="var">spielr_name</span>) <span class="cm"># 💥 NameError: name 'spielr_name' is not defined (Tippfehler!)</span></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fehler 4: TypeError -->
|
||||||
|
<div class="box box-warning">
|
||||||
|
<div class="box-title">4. TypeError (Falscher Datentyp)</div>
|
||||||
|
<p>Tritt auf, wenn man Operationen mit unpassenden Typen versucht (z.B. Zahl an Text anhängen mit <code>+</code> statt f-String).</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="code-container">
|
||||||
|
<div class="code-header"><span>Vergleich: TypeError</span></div>
|
||||||
|
<pre><span class="var">punkte</span> = <span class="num">100</span>
|
||||||
|
<span class="cm"># ❌ Falsch:</span>
|
||||||
|
<span class="fn">print</span>(<span class="str">"Du hast "</span> + <span class="var">punkte</span> + <span class="str">" Punkte!"</span>) <span class="cm"># 💥 TypeError: can only concatenate str to str</span>
|
||||||
|
|
||||||
|
<span class="cm"># ✅ Richtig mit f-String:</span>
|
||||||
|
<span class="fn">print</span>(<span class="str">f"Du hast {punkte} Punkte!"</span>)</pre>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 3. Detektiv-Aufgabe -->
|
||||||
|
<section class="card">
|
||||||
|
<h2>3. 🕵️♀️ Deine Detektiv-Aufgabe in <code>aufgabe.py</code></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In der Datei <code>00_fehlersuche_und_grundlagen/aufgabe.py</code> findest du ein kleines Programm für ein Quiz-Spiel, in dem sich <strong>5 typische Fehler</strong> versteckt haben!
|
||||||
|
</p>
|
||||||
|
<p>Deine Mission als Code-Detektivin:</p>
|
||||||
|
|
||||||
|
<ul class="task-list">
|
||||||
|
<li class="task-item">
|
||||||
|
<input type="checkbox" class="task-checkbox" id="b1">
|
||||||
|
<label for="b1" class="task-label">
|
||||||
|
<strong>Bug 1 (SyntaxError):</strong> Finde den fehlenden Doppelpunkt in der Funktionsdefinition <code>berechne_endstand</code>.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li class="task-item">
|
||||||
|
<input type="checkbox" class="task-checkbox" id="b2">
|
||||||
|
<label for="b2" class="task-label">
|
||||||
|
<strong>Bug 2 (IndentationError):</strong> Korrigiere die falsche Einrückung in der <code>if</code>-Bedingung.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li class="task-item">
|
||||||
|
<input type="checkbox" class="task-checkbox" id="b3">
|
||||||
|
<label for="b3" class="task-label">
|
||||||
|
<strong>Bug 3 (NameError):</strong> Korrigiere den Tippfehler beim Variablennamen <code>spieler_punkte</code>.
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li class="task-item">
|
||||||
|
<input type="checkbox" class="task-checkbox" id="b4">
|
||||||
|
<label for="b4" class="task-label">
|
||||||
|
<strong>Bug 4 (TypeError):</strong> Korrigiere die Textzusammensetzung in <code>formatierte_ausgabe</code> (nutze einen sauberen f-String).
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li class="task-item">
|
||||||
|
<input type="checkbox" class="task-checkbox" id="b5">
|
||||||
|
<label for="b5" class="task-label">
|
||||||
|
<strong>Bug 5 (Logik-Fehler):</strong> Die Funktion <code>ist_sieger</code> soll ab <strong>50 Punkten oder mehr</strong> <code>True</code> zurückgeben (prüfe <code>>=</code> statt <code>></code>).
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>🔍 Tipp zur Ausführung im Terminal</summary>
|
||||||
|
<div class="details-content">
|
||||||
|
<p>Führe das Skript einfach direkt im Terminal aus:</p>
|
||||||
|
<div class="code-container">
|
||||||
|
<pre><code>python3 aufgabe.py</code></pre>
|
||||||
|
</div>
|
||||||
|
<p>Python zeigt dir sofort den ersten Fehler an. Repariere ihn, führe das Skript erneut aus und arbeite dich so Schritt für Schritt durch!</p>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 4. Testen & Navigation -->
|
||||||
|
<section class="card">
|
||||||
|
<h2>4. 🧪 Detektiv-Prüfung abschließen</h2>
|
||||||
|
<p>Sobald du alle Fehler behoben hast, teste deine Lösung mit:</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="../01_einstieg_klassen/index.html" class="btn">Weiter zu Kapitel 01: Klassen →</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
40
00_fehlersuche_und_grundlagen/musterloesung.py
Normal file
40
00_fehlersuche_und_grundlagen/musterloesung.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
"""
|
||||||
|
Vorkapitel 00: Python-Detektivin – Musterlösung
|
||||||
|
==============================================
|
||||||
|
Hier ist die vollständig fehlerfreie Version des Skripts.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# BUG 1 & 2 behoben: Doppelpunkt hinzugefügt und 'gesamt += 5' sauber eingerückt:
|
||||||
|
def berechne_endstand(basis_punkte, bonus):
|
||||||
|
gesamt = basis_punkte + bonus
|
||||||
|
if bonus > 10:
|
||||||
|
gesamt += 5
|
||||||
|
return gesamt
|
||||||
|
|
||||||
|
|
||||||
|
# BUG 3 behoben: Tippfehler 'spiler_punkte' -> 'spieler_punkte' korrigiert:
|
||||||
|
def punkte_multiplizieren(spieler_punkte, faktor):
|
||||||
|
ergebnis = spieler_punkte * faktor
|
||||||
|
return ergebnis
|
||||||
|
|
||||||
|
|
||||||
|
# BUG 4 behoben: f-String verwendet, um Zahl und Text sauber zu verbinden:
|
||||||
|
def formatierte_ausgabe(name, punkte):
|
||||||
|
text = f"Spieler {name} hat {punkte} Punkte!"
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
# BUG 5 behoben: >= statt > verwendet:
|
||||||
|
def ist_sieger(punkte):
|
||||||
|
if punkte >= 50:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🕵️♀️ --- CODE-DETEKTIVIN QUIZ TEST (Musterlösung) --- 🕵️♀️")
|
||||||
|
print("Endstand (40):", berechne_endstand(20, 15))
|
||||||
|
print("Multipliziert (30):", punkte_multiplizieren(10, 3))
|
||||||
|
print("Ausgabe:", formatierte_ausgabe("Mia", 50))
|
||||||
|
print("Sieg bei 50:", ist_sieger(50))
|
||||||
63
00_fehlersuche_und_grundlagen/test_aufgabe.py
Normal file
63
00_fehlersuche_und_grundlagen/test_aufgabe.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import importlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
|
|
||||||
|
|
||||||
|
class TestKapitel00(unittest.TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
# Wenn ein Test-Runner vorher 'aufgabe' durch ein anderes Modul ersetzt hat (z.B. musterloesung):
|
||||||
|
if hasattr(cls, "modul_name"):
|
||||||
|
cls.mod = importlib.import_module(cls.modul_name)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
cls.mod = importlib.import_module("aufgabe")
|
||||||
|
except SyntaxError as e:
|
||||||
|
cls.mod = None
|
||||||
|
cls.import_error = f"SyntaxError in 'aufgabe.py': {e}. Überprüfe Doppelpunkte und Einrückungen!"
|
||||||
|
except Exception as e:
|
||||||
|
cls.mod = None
|
||||||
|
cls.import_error = f"Fehler beim Import von 'aufgabe.py': {e}"
|
||||||
|
|
||||||
|
def _get_modul(self):
|
||||||
|
if getattr(self, "mod", None) is None:
|
||||||
|
err = getattr(self, "import_error", "aufgabe.py konnte nicht importiert werden")
|
||||||
|
self.fail(f"❌ {err}")
|
||||||
|
return self.mod
|
||||||
|
|
||||||
|
def test_01_berechne_endstand(self):
|
||||||
|
"""Prüft berechne_endstand (Syntax & Einrückung behoben)."""
|
||||||
|
mod = self._get_modul()
|
||||||
|
self.assertTrue(hasattr(mod, "berechne_endstand"), "Funktion 'berechne_endstand' fehlt!")
|
||||||
|
self.assertEqual(mod.berechne_endstand(20, 15), 40, "berechne_endstand(20, 15) sollte 40 sein (inkl. Bonus)!")
|
||||||
|
self.assertEqual(mod.berechne_endstand(20, 5), 25, "berechne_endstand(20, 5) sollte 25 sein!")
|
||||||
|
|
||||||
|
def test_02_punkte_multiplizieren(self):
|
||||||
|
"""Prüft punkte_multiplizieren (Tippfehler NameError behoben)."""
|
||||||
|
mod = self._get_modul()
|
||||||
|
self.assertTrue(hasattr(mod, "punkte_multiplizieren"), "Funktion 'punkte_multiplizieren' fehlt!")
|
||||||
|
self.assertEqual(mod.punkte_multiplizieren(10, 3), 30)
|
||||||
|
self.assertEqual(mod.punkte_multiplizieren(7, 2), 14)
|
||||||
|
|
||||||
|
def test_03_formatierte_ausgabe(self):
|
||||||
|
"""Prüft formatierte_ausgabe (TypeError behoben)."""
|
||||||
|
mod = self._get_modul()
|
||||||
|
self.assertTrue(hasattr(mod, "formatierte_ausgabe"), "Funktion 'formatierte_ausgabe' fehlt!")
|
||||||
|
ergebnis = mod.formatierte_ausgabe("Mia", 50)
|
||||||
|
self.assertEqual(ergebnis, "Spieler Mia hat 50 Punkte!")
|
||||||
|
|
||||||
|
def test_04_ist_sieger_grenzwert(self):
|
||||||
|
"""Prüft Logik von ist_sieger (>= 50 Punkte)."""
|
||||||
|
mod = self._get_modul()
|
||||||
|
self.assertTrue(hasattr(mod, "ist_sieger"), "Funktion 'ist_sieger' fehlt!")
|
||||||
|
self.assertTrue(mod.ist_sieger(50), "Fehler: Genau 50 Punkte müssen True (Sieg) ergeben (>= 50)!")
|
||||||
|
self.assertTrue(mod.ist_sieger(100), "100 Punkte müssen True ergeben!")
|
||||||
|
self.assertFalse(mod.ist_sieger(49), "49 Punkte dürfen noch kein Sieg sein (False)!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main(verbosity=2)
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
<nav class="nav-links">
|
<nav class="nav-links">
|
||||||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||||||
<span>›</span>
|
<span>›</span>
|
||||||
|
<a href="../00_fehlersuche_und_grundlagen/index.html">Kapitel 00</a>
|
||||||
|
<span>›</span>
|
||||||
<span style="color: white; font-weight: 600;">Kapitel 01</span>
|
<span style="color: white; font-weight: 600;">Kapitel 01</span>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header-badge">Kapitel 01</div>
|
<div class="header-badge">Kapitel 01</div>
|
||||||
|
|
@ -278,7 +280,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-nav">
|
<div class="footer-nav">
|
||||||
<a href="../index.html" class="btn btn-secondary">← Zurück zur Übersicht</a>
|
<a href="../00_fehlersuche_und_grundlagen/index.html" class="btn btn-secondary">← Zurück zu Kapitel 00</a>
|
||||||
<a href="../02_init_und_self/index.html" class="btn">Weiter zu Kapitel 02 →</a>
|
<a href="../02_init_und_self/index.html" class="btn">Weiter zu Kapitel 02 →</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
27
README.md
27
README.md
|
|
@ -12,6 +12,7 @@ Die Übungen sind so aufgebaut, dass jedes Kapitel auf dem vorherigen aufbaut:
|
||||||
|
|
||||||
| Kapitel | Thema | Was du lernst |
|
| Kapitel | Thema | Was du lernst |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
|
| **[00. Fehlersuche & Grundlagen](./00_fehlersuche_und_grundlagen/)** | Warm-up & Debugging | Tracebacks lesen, Einrückungen (`IndentationError`), Typfehler & Detektiv-Aufgabe |
|
||||||
| **[01. Einstieg in Klassen](./01_einstieg_klassen/)** | Warum Klassen? | Bauplan vs. Objekt, Instanziierung & Attribute |
|
| **[01. Einstieg in Klassen](./01_einstieg_klassen/)** | Warum Klassen? | Bauplan vs. Objekt, Instanziierung & Attribute |
|
||||||
| **[02. Konstruktor & self](./02_init_und_self/)** | `__init__` & `self` | Objekte sauber mit Startwerten initialisieren |
|
| **[02. Konstruktor & self](./02_init_und_self/)** | `__init__` & `self` | Objekte sauber mit Startwerten initialisieren |
|
||||||
| **[03. Methoden & Verhalten](./03_methoden_und_verhalten/)** | Methoden & Interaktion | Objekte können handeln & miteinander interagieren |
|
| **[03. Methoden & Verhalten](./03_methoden_und_verhalten/)** | Methoden & Interaktion | Objekte können handeln & miteinander interagieren |
|
||||||
|
|
@ -24,30 +25,28 @@ Die Übungen sind so aufgebaut, dass jedes Kapitel auf dem vorherigen aufbaut:
|
||||||
## 📁 Aufbau eines Kapitels
|
## 📁 Aufbau eines Kapitels
|
||||||
|
|
||||||
In jedem Kapitelordner findest du:
|
In jedem Kapitelordner findest du:
|
||||||
1. **`README.md`**: Eine verständliche Erklärung mit Analogien aus dem Alltag und Codebeispielen.
|
1. **`index.html`**: Eine interaktive, schön gestaltete Webseite mit ausführlichen Erklärungen, Vollbeispielen und aufklappbaren Lösungshinweisen.
|
||||||
2. **`aufgabe.py`**: Dein Arbeitsblatt! Hier steht der Starter-Code mit klaren `TODO`-Kommentaren.
|
2. **`README.md`**: Die Erklärung im Markdown-Format.
|
||||||
3. **`test_aufgabe.py`**: Automatische Tests, mit denen du deine Lösung jederzeit überprüfen kannst.
|
3. **`aufgabe.py`**: Dein Arbeitsblatt! Hier steht der Starter-Code mit klaren `TODO`-Kommentaren.
|
||||||
4. **`musterloesung.py`**: Eine ausführlich kommentierte Beispiellösung (falls du mal nicht weiterkommst oder vergleichen möchtest).
|
4. **`test_aufgabe.py`**: Automatische Tests, mit denen du deine Lösung jederzeit überprüfen kannst.
|
||||||
|
5. **`musterloesung.py`**: Eine ausführlich kommentierte Beispiellösung.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Wie du vorgehst
|
## 🚀 Wie du vorgehst
|
||||||
|
|
||||||
1. Öffne den Ordner des aktuellen Kapitels (z.B. `01_einstieg_klassen`).
|
1. Öffne den Ordner des aktuellen Kapitels (z.B. `00_fehlersuche_und_grundlagen`).
|
||||||
2. Lies dir die Erklärung in der jeweiligen `README.md` durch.
|
2. Öffne die `index.html` im Browser oder lies die `README.md`.
|
||||||
3. Öffne `aufgabe.py` und bearbeite die nummerierten `TODO`s.
|
3. Öffne `aufgabe.py` und bearbeite die nummerierten `TODO`s / Bugs.
|
||||||
4. Führe die Tests aus, um deine Lösung zu prüfen:
|
4. Führe die Tests aus, um deine Lösung zu prüfen:
|
||||||
```bash
|
```bash
|
||||||
# Aus dem Hauptverzeichnis:
|
|
||||||
python3 -m unittest 01_einstieg_klassen/test_aufgabe.py
|
|
||||||
|
|
||||||
# Oder direkt im Ordner:
|
|
||||||
cd 01_einstieg_klassen
|
|
||||||
python3 test_aufgabe.py
|
python3 test_aufgabe.py
|
||||||
```
|
```
|
||||||
5. Wenn alle Tests mit einem grünen `OK` durchlaufen: **Herzlichen Glückwunsch!** Du bist bereit für das nächste Kapitel! 🏆
|
5. Wenn alle Tests mit einem grünen `OK` durchlaufen: **Herzlichen Glückwunsch!** Du bist bereit für das nächste Kapitel! 🏆
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 💡 Tipp zum Lernen
|
## 💡 Gesamten Fortschritt prüfen
|
||||||
Versuche zuerst selbst eine Lösung zu finden. Wenn ein Fehler auftritt, lies die Fehlermeldung der Tests aufmerksam durch – sie gibt dir oft schon den entscheidenden Hinweis! Wenn du gar nicht weiterkommst, wirf einen Blick in `musterloesung.py` und versuche zu verstehen, wie das Problem gelöst wurde.
|
```bash
|
||||||
|
python3 test_all.py
|
||||||
|
```
|
||||||
|
|
|
||||||
32
index.html
32
index.html
|
|
@ -26,26 +26,36 @@
|
||||||
Jetzt machen wir den nächsten großen Schritt in der Softwareentwicklung: <strong>Klassen & Objekte</strong>!
|
Jetzt machen wir den nächsten großen Schritt in der Softwareentwicklung: <strong>Klassen & Objekte</strong>!
|
||||||
</p>
|
</p>
|
||||||
<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.
|
Damit du beim Programmieren nie an kleinen Syntaxfehlern verzweifelst, starten wir mit einem kurzen <strong>Warm-up zur Fehlersuche (Kapitel 00)</strong>, bevor es mit den Klassen losgeht.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="box box-analogie">
|
<div class="box box-analogie">
|
||||||
<div class="box-title">🏗️ Die Grundidee in einem Satz:</div>
|
<div class="box-title">🏗️ Die Grundidee von OOP in einem Satz:</div>
|
||||||
Eine <strong>Klasse</strong> ist wie ein Bauplan (oder eine Plätzchen-Ausstechform). Ein <strong>Objekt</strong> ist das fertige Haus (oder das gebackene Plätzchen), das nach diesem Bauplan entstanden ist!
|
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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Roadmap Grid -->
|
<!-- Roadmap Grid -->
|
||||||
<section>
|
<section>
|
||||||
<h2 style="margin: 30px 0 15px 0; color: var(--text-main); font-size: 1.5rem;">🗺️ Dein Lernpfad (Kapitel 01 bis 06)</h2>
|
<h2 style="margin: 30px 0 15px 0; color: var(--text-main); font-size: 1.5rem;">🗺️ Dein Lernpfad (Kapitel 00 bis 06)</h2>
|
||||||
<div class="roadmap-grid">
|
<div class="roadmap-grid">
|
||||||
|
|
||||||
|
<!-- Kapitel 0 -->
|
||||||
|
<a href="00_fehlersuche_und_grundlagen/index.html" class="roadmap-card" style="border-left: 4px solid var(--purple);">
|
||||||
|
<div>
|
||||||
|
<span class="roadmap-number" style="background: var(--purple-light); color: var(--purple);">Vorkapitel 00</span>
|
||||||
|
<div class="roadmap-title">🔍 Fehlersuche & Bugs</div>
|
||||||
|
<div class="roadmap-desc">Tracebacks richtig lesen, Einrückungsfehler (IndentationError), Typfehler und eine interaktive Detektiv-Aufgabe.</div>
|
||||||
|
</div>
|
||||||
|
<div class="roadmap-footer">Vorkapitel öffnen →</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<!-- Kapitel 1 -->
|
<!-- Kapitel 1 -->
|
||||||
<a href="01_einstieg_klassen/index.html" class="roadmap-card">
|
<a href="01_einstieg_klassen/index.html" class="roadmap-card">
|
||||||
<div>
|
<div>
|
||||||
<span class="roadmap-number">Kapitel 01</span>
|
<span class="roadmap-number">Kapitel 01</span>
|
||||||
<div class="roadmap-title">🐶 Die erste Klasse</div>
|
<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 class="roadmap-desc">Was ist eine Klasse? Bauplan vs. Objekt, Instanziierung und erste Attribute am Haustier- & Fahrrad-Beispiel.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -55,7 +65,7 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="roadmap-number">Kapitel 02</span>
|
<span class="roadmap-number">Kapitel 02</span>
|
||||||
<div class="roadmap-title">💳 Konstruktor & self</div>
|
<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 class="roadmap-desc">Wie <code>__init__</code> Objekte startklar macht und was <code>self</code> bedeutet (Smartphone- & Bankkonto-App).</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -65,7 +75,7 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="roadmap-number">Kapitel 03</span>
|
<span class="roadmap-number">Kapitel 03</span>
|
||||||
<div class="roadmap-title">⚔️ Methoden & Verhalten</div>
|
<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 class="roadmap-desc">Objekte führen Aktionen aus! Interaktion zwischen Objekten in Rennautos und RPG-Heldenduellen.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -75,7 +85,7 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="roadmap-number">Kapitel 04</span>
|
<span class="roadmap-number">Kapitel 04</span>
|
||||||
<div class="roadmap-title">🧾 Schöne Textausgabe</div>
|
<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 class="roadmap-desc">Wie man <code>print(objekt)</code> mit <code>__str__</code> lesbar macht und Objekte im Warenkorb & bei Pizza-Bestellungen sammelt.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -85,7 +95,7 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="roadmap-number">Kapitel 05</span>
|
<span class="roadmap-number">Kapitel 05</span>
|
||||||
<div class="roadmap-title">🎵 Komposition & Playlists</div>
|
<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 class="roadmap-desc">Objekte verwalten andere Objekte: Song-Suche, Längenberechnung und Filter in Spotify-Playlists & Schulklassen.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roadmap-footer">Kapitel öffnen →</div>
|
<div class="roadmap-footer">Kapitel öffnen →</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -107,9 +117,9 @@
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h2>🚀 Wie du vorgehst (Schritt-für-Schritt)</h2>
|
<h2>🚀 Wie du vorgehst (Schritt-für-Schritt)</h2>
|
||||||
<ol style="margin-left: 20px; margin-bottom: 15px;">
|
<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;">Wähle das nächste offene Kapitel aus der Liste oben (am besten startest du mit Kapitel 00).</li>
|
||||||
<li style="margin-bottom: 8px;">Lies die Erklärungen und schau dir die Codebeispiele und „Stolperfallen“ an.</li>
|
<li style="margin-bottom: 8px;">Lies die Erklärungen und schau dir die vollständigen Codebeispiele 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;">Öffne die <code>aufgabe.py</code> im entsprechenden Kapitelordner und löse die Aufgaben.</li>
|
||||||
<li style="margin-bottom: 8px;">
|
<li style="margin-bottom: 8px;">
|
||||||
Führe im Terminal den automatischen Test aus:
|
Führe im Terminal den automatischen Test aus:
|
||||||
<div class="code-container" style="margin: 10px 0;">
|
<div class="code-container" style="margin: 10px 0;">
|
||||||
|
|
|
||||||
24
test_all.py
24
test_all.py
|
|
@ -11,6 +11,7 @@ import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
KAPITEL = [
|
KAPITEL = [
|
||||||
|
("Kapitel 00: Python-Fehlersuche (Warm-up)", "00_fehlersuche_und_grundlagen"),
|
||||||
("Kapitel 01: Einstieg in Klassen", "01_einstieg_klassen"),
|
("Kapitel 01: Einstieg in Klassen", "01_einstieg_klassen"),
|
||||||
("Kapitel 02: Konstruktor & self", "02_init_und_self"),
|
("Kapitel 02: Konstruktor & self", "02_init_und_self"),
|
||||||
("Kapitel 03: Methoden & Verhalten", "03_methoden_und_verhalten"),
|
("Kapitel 03: Methoden & Verhalten", "03_methoden_und_verhalten"),
|
||||||
|
|
@ -21,9 +22,9 @@ KAPITEL = [
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
root = Path(__file__).parent.resolve()
|
root = Path(__file__).parent.resolve()
|
||||||
print("=" * 60)
|
print("=" * 65)
|
||||||
print("🎓 PYTHON OOP ÜBUNGSREIHE – GESAMTFORTSCHRITT")
|
print("🎓 PYTHON OOP ÜBUNGSREIHE – GESAMTFORTSCHRITT")
|
||||||
print("=" * 60)
|
print("=" * 65)
|
||||||
|
|
||||||
gesamt_bestanden = 0
|
gesamt_bestanden = 0
|
||||||
|
|
||||||
|
|
@ -42,31 +43,30 @@ def main():
|
||||||
runner = unittest.TextTestRunner(stream=open("/dev/null", "w"), verbosity=0)
|
runner = unittest.TextTestRunner(stream=open("/dev/null", "w"), verbosity=0)
|
||||||
result = runner.run(suite)
|
result = runner.run(suite)
|
||||||
|
|
||||||
# Modul aus sys.path und sys.modules entfernen für saubere Isolation
|
# Module für saubere Isolation entfernen
|
||||||
if str(kapitel_pfad) in sys.path:
|
if str(kapitel_pfad) in sys.path:
|
||||||
sys.path.remove(str(kapitel_pfad))
|
sys.path.remove(str(kapitel_pfad))
|
||||||
if "aufgabe" in sys.modules:
|
for m in list(sys.modules.keys()):
|
||||||
del sys.modules["aufgabe"]
|
if m in ("aufgabe", "test_aufgabe", "musterloesung"):
|
||||||
if "test_aufgabe" in sys.modules:
|
del sys.modules[m]
|
||||||
del sys.modules["test_aufgabe"]
|
|
||||||
|
|
||||||
anzahl_tests = result.testsRun
|
anzahl_tests = result.testsRun
|
||||||
erfolgreich = result.wasSuccessful() and anzahl_tests > 0
|
erfolgreich = result.wasSuccessful() and anzahl_tests > 0
|
||||||
|
|
||||||
if erfolgreich:
|
if erfolgreich:
|
||||||
print(f" ✅ {titel:42s} ({anzahl_tests}/{anzahl_tests} Tests OK)")
|
print(f" ✅ {titel:45s} ({anzahl_tests}/{anzahl_tests} Tests OK)")
|
||||||
gesamt_bestanden += 1
|
gesamt_bestanden += 1
|
||||||
else:
|
else:
|
||||||
fehlgeschlagen = len(result.failures) + len(result.errors)
|
fehlgeschlagen = len(result.failures) + len(result.errors)
|
||||||
print(f" ⏳ {titel:42s} (Noch offen / {fehlgeschlagen} Fehler)")
|
print(f" ⏳ {titel:45s} (Noch offen / {fehlgeschlagen} Fehler)")
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 65)
|
||||||
print(f"Ergebnis: {gesamt_bestanden} von {len(KAPITEL)} Kapiteln vollständig gelöst!")
|
print(f"Ergebnis: {gesamt_bestanden} von {len(KAPITEL)} Kapiteln vollständig gelöst!")
|
||||||
if gesamt_bestanden == len(KAPITEL):
|
if gesamt_bestanden == len(KAPITEL):
|
||||||
print("🏆 PERFEKT! Du hast alle OOP-Aufgaben mit Bravour gemeistert! 🎉")
|
print("🏆 PERFEKT! Du hast alle Aufgaben mit Bravour gemeistert! 🎉")
|
||||||
else:
|
else:
|
||||||
print("💡 Öffne das nächste offene Kapitel und starte mit aufgabe.py!")
|
print("💡 Öffne das nächste offene Kapitel und starte mit aufgabe.py!")
|
||||||
print("=" * 60)
|
print("=" * 65)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue