Knowledge Hub

Learning Journey

Lösungen & Erklärungen

Zu jeder Python-Themen-Aufgabe: erst Vorgehen, dann Lösung. Ideal parallel zu `/journey/uebungen/python-themen`.

Gesamtfortschritt

0%

Nächster Schritt: Kleine Python-Programme

  1. 01

    Kleine Python-Programme

    Vorgehen + Lösung: Begrüßung, Taschenrechner, Primzahl, Rate-Spiel.

    Offen · 2 Themen
    • input/float und Verzweigungen erklären
    • Zufall + while True verstehen
    inputif/elifPrimzahlrandom

    1.1–1.2 Begrüßen & Taschenrechner

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: input speichern / float + Operator. Lösung: f-String und if/elif-Kette inkl. Division durch 0.

    • Vorgehen: `input()` → Variable → Ausgabe
    • Lösung: `float(input(…))` und `if op == "+"` …
    • Division: `b != 0` prüfen

    1.1 Nutzer begrüßen · python

    name = input("Wie heißt du? ")
    print(f"Hallo {name}, schön dich kennenzulernen!")

    1.2 Taschenrechner · python

    a = float(input("Erste Zahl: "))
    b = float(input("Zweite Zahl: "))
    op = input("Rechenart (+,-,*,/): ")
    
    if op == "+":
        print(a + b)
    elif op == "-":
        print(a - b)
    elif op == "*":
        print(a * b)
    elif op == "/":
        if b != 0:
            print(a / b)
        else:
            print("Division durch 0 nicht möglich")
    else:
        print("Unbekannte Rechenart")

    1.3–1.4 Primzahl & Erraten

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: Teilbarkeit / Zufallszahl + Hinweise. Lösung: Schleife 2..n-1 bzw. while True mit break.

    • Vorgehen: nur durch 1 und sich selbst teilbar
    • Lösung: `ist_primzahl` mit `%`
    • Lösung: `random.randint` + höher/niedriger

    1.3 Primzahl prüfen · python

    def ist_primzahl(zahl):
        if zahl < 2:
            return False
        for i in range(2, zahl):
            if zahl % i == 0:
                return False
        return True
    
    print(ist_primzahl(7))   # True
    print(ist_primzahl(8))   # False

    1.4 Zahlen erraten · python

    import random
    
    zielzahl = random.randint(1, 100)
    
    while True:
        versuch = int(input("Rate eine Zahl (1-100): "))
        if versuch < zielzahl:
            print("Höher!")
        elif versuch > zielzahl:
            print("Niedriger!")
        else:
            print("Richtig!")
            break
  2. 02

    APIs

    Vorgehen + Lösung für requests, Open-Meteo, Witze und json.dump.

    Offen · 2 Themen
    • API-Antworten als Dict/Liste lesen
    • Ergebnisse lokal speichern
    requestsOpen-Meteojson.dump

    2.1–2.3 GET & Formatierung

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: get → .json → Felder. Lösung: users-Namen, Temperatur Bremen, hole_zufallswitz().

    • Vorgehen: `.json()` liefert Python-Struktur
    • Lösung: `user["name"]` / `current_weather`
    • Lösung: setup + punchline formatieren

    2.1 Nutzer von JSONPlaceholder holen · python

    import requests
    
    response = requests.get("https://jsonplaceholder.typicode.com/users")
    users = response.json()
    
    for user in users:
        print(user["name"])

    2.2 Wetterdaten (Open-Meteo, kein API-Key nötig) · python

    import requests
    
    lat, lon = 53.0793, 8.8017  # Bremen
    url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&current_weather=true"
    
    response = requests.get(url)
    data = response.json()
    
    temperatur = data["current_weather"]["temperature"]
    print(f"Aktuelle Temperatur: {temperatur}°C")

    2.3 Zufallswitz-Funktion · python

    import requests
    
    def hole_zufallswitz():
        response = requests.get("https://official-joke-api.appspot.com/random_joke")
        witz = response.json()
        return f"{witz['setup']} — {witz['punchline']}"
    
    print(hole_zufallswitz())

    2.4 Lokal speichern

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: Ergebnis direkt dump-en. Lösung: users.json mit indent=2.

    • Vorgehen: Liste/Dict → `json.dump`
    • Lösung: `with open("users.json", "w")`

    2.4 API-Daten zusätzlich lokal speichern · python

    import requests
    import json
    
    response = requests.get("https://jsonplaceholder.typicode.com/users")
    users = response.json()
    
    with open("users.json", "w") as f:
        json.dump(users, f, indent=2)
    
    print("Gespeichert!")
  3. 03

    Daten verarbeiten

    Manuelle Statistik, Wortanalyse, Filter/Sort und CSV-Umsatz.

    Offen · 2 Themen
    • Schleifen-Logik hinter Built-ins verstehen
    • DictReader nutzen
    Schleifensortedcsv

    3.1–3.2 Statistik & Wörter

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: laufend vergleichen/zählen. Lösung: Min/Max/Summe; .get für Buchstaben.

    • Vorgehen: wie Built-ins intern arbeiten
    • Lösung: Startwert = erstes Element
    • Lösung: `buchstaben_count.get(erster, 0) + 1`

    3.1 Summe, Durchschnitt, Min, Max ohne eingebaute Funktionen · python

    zahlen = [4, 8, 2, 9, 5]
    
    summe = 0
    minimum = zahlen[0]
    maximum = zahlen[0]
    
    for z in zahlen:
        summe += z
        if z < minimum:
            minimum = z
        if z > maximum:
            maximum = z
    
    durchschnitt = summe / len(zahlen)
    print(summe, durchschnitt, minimum, maximum)

    3.2 Längstes Wort + Anfangsbuchstaben zählen · python

    woerter = ["Apfel", "Birne", "Ananas", "Kiwi"]
    
    laengstes = woerter[0]
    for w in woerter:
        if len(w) > len(laengstes):
            laengstes = w
    print("Längstes Wort:", laengstes)
    
    buchstaben_count = {}
    for w in woerter:
        erster = w[0]
        buchstaben_count[erster] = buchstaben_count.get(erster, 0) + 1
    
    print(buchstaben_count)

    3.3–3.4 Produkte & CSV

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: Comprehension + key=; DictReader. Lösung: Filter >50, Umsatz aggregieren.

    • Lösung: `[p for p in produkte if p["preis"] > 50]`
    • Lösung: Strings aus CSV mit int/float casten

    3.3 Produkte filtern & sortieren · python

    produkte = [
        {"name": "Kette", "preis": 25},
        {"name": "Ring", "preis": 60},
        {"name": "Armband", "preis": 45},
    ]
    
    teure_produkte = [p for p in produkte if p["preis"] > 50]
    sortiert = sorted(produkte, key=lambda p: p["preis"])
    
    print(teure_produkte)
    print(sortiert)

    3.4 CSV einlesen & Umsatz berechnen · python

    import csv
    
    umsatz_pro_produkt = {}
    
    with open("verkaeufe.csv", newline="") as f:
        reader = csv.DictReader(f)
        for zeile in reader:
            produkt = zeile["Produkt"]
            menge = int(zeile["Menge"])
            preis = float(zeile["Preis"])
            umsatz = menge * preis
            umsatz_pro_produkt[produkt] = umsatz_pro_produkt.get(produkt, 0) + umsatz
    
    print(umsatz_pro_produkt)
  4. 04

    Dateien lesen/schreiben

    with open, Append-Tagebuch und JSON Roundtrip — erklärt.

    Offen · 1 Themen
    • Modi w/r/a unterscheiden
    • json.dump/load sicher einsetzen
    with openappendjson

    4.1–4.4 Datei-I/O

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: with schließt automatisch. Lösung: schreiben, zeilenweise lesen, Tagebuch, JSON.

    • Vorgehen: `"w"` überschreibt, `"a"` hängt an
    • Lösung: `strip()` entfernt Zeilenumbruch
    • Lösung: `json.dump` / `json.load`

    4.1 Text in Datei schreiben · python

    def notiz_schreiben(text):
        with open("notizen.txt", "w") as f:
            f.write(text)
    
    notiz_schreiben("Meine erste Notiz")

    4.2 Datei zeilenweise lesen · python

    def notiz_lesen():
        with open("notizen.txt", "r") as f:
            for zeile in f:
                print(zeile.strip())   # strip() entfernt den Zeilenumbruch
    
    notiz_lesen()

    4.3 Tagebuch mit Anhängen · python

    from datetime import datetime
    
    def eintrag_hinzufuegen(text):
        zeitstempel = datetime.now().strftime("%Y-%m-%d %H:%M")
        with open("tagebuch.txt", "a") as f:
            f.write(f"[{zeitstempel}] {text}\n")
    
    eintrag_hinzufuegen("Heute Python geübt.")

    4.4 JSON schreiben & lesen · python

    import json
    
    personen = [{"name": "Anna", "alter": 25}, {"name": "Ben", "alter": 30}]
    
    with open("personen.json", "w") as f:
        json.dump(personen, f, indent=2)
    
    with open("personen.json", "r") as f:
        geladen = json.load(f)
    
    print(geladen)
  5. 05

    Fehlerbehandlung

    try/except-Muster und eigene Exception-Klasse mit raise.

    Offen · 1 Themen
    • Spezifische Exceptions bevorzugen
    • Eigene Errors modellieren
    try/exceptraiseException

    5.1–5.4 Exceptions

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: while+try; gezielte except. Lösung: Zahl, Division, FileNotFound, UngueltigesAlterError.

    • Vorgehen: bei Erfolg `break`, sonst Meldung
    • Lösung: `except ZeroDivisionError`
    • Lösung: `raise UngueltigesAlterError(…)`

    5.1 Erneut fragen bei ungültiger Zahl · python

    while True:
        try:
            zahl = int(input("Gib eine Zahl ein: "))
            break
        except ValueError:
            print("Das ist keine gültige Zahl, versuch's nochmal.")
    
    print("Du hast eingegeben:", zahl)

    5.2 Sichere Division · python

    def sichere_division(a, b):
        try:
            return a / b
        except ZeroDivisionError:
            return "Fehler: Division durch 0 nicht möglich"
    
    print(sichere_division(10, 2))
    print(sichere_division(10, 0))

    5.3 Datei-Fehler abfangen · python

    try:
        with open("nicht_vorhanden.txt") as f:
            inhalt = f.read()
    except FileNotFoundError:
        print("Die Datei wurde nicht gefunden.")

    5.4 Eigene Exception-Klasse · python

    class UngueltigesAlterError(Exception):
        pass
    
    def alter_setzen(alter):
        if alter < 0:
            raise UngueltigesAlterError("Alter darf nicht negativ sein")
        return alter
    
    try:
        alter_setzen(-5)
    except UngueltigesAlterError as e:
        print("Fehler:", e)
  6. 06

    Funktionen und Klassen

    Palindrom, Auto, Warenkorb und Manager mit super().__init__.

    Offen · 1 Themen
    • Methoden und Vererbung nachvollziehen
    • super() erklären
    classsuperMethoden

    6.1–6.4 Funktionen & OOP

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: Slice/Jahr/Liste/super. Lösung: ist_palindrom, Auto.alter, Warenkorb, Manager.

    • Lösung: `text == text[::-1]`
    • Lösung: `datetime.now().year - baujahr`
    • Vorgehen: `super().__init__` vermeidet Duplikate

    6.1 Palindrom prüfen · python

    def ist_palindrom(text):
        text = text.lower()
        return text == text[::-1]
    
    print(ist_palindrom("anna"))    # True
    print(ist_palindrom("hallo"))   # False

    6.2 Klasse Auto mit Altersberechnung · python

    from datetime import datetime
    
    class Auto:
        def __init__(self, marke, baujahr):
            self.marke = marke
            self.baujahr = baujahr
    
        def alter(self):
            return datetime.now().year - self.baujahr
    
    mein_auto = Auto("BMW", 2018)
    print(mein_auto.alter())

    6.3 Klasse Warenkorb · python

    class Warenkorb:
        def __init__(self):
            self.produkte = []
    
        def hinzufuegen(self, name, preis):
            self.produkte.append({"name": name, "preis": preis})
    
        def entfernen(self, name):
            self.produkte = [p for p in self.produkte if p["name"] != name]
    
        def gesamtpreis(self):
            return sum(p["preis"] for p in self.produkte)
    
    korb = Warenkorb()
    korb.hinzufuegen("Kette", 25)
    korb.hinzufuegen("Ring", 40)
    print(korb.gesamtpreis())   # 65

    6.4 Vererbung: Mitarbeiter → Manager · python

    class Mitarbeiter:
        def __init__(self, name, position):
            self.name = name
            self.position = position
    
    class Manager(Mitarbeiter):
        def __init__(self, name, position, team):
            super().__init__(name, position)
            self.team = team   # Liste von Mitarbeiter-Objekten
    
        def team_anzeigen(self):
            for m in self.team:
                print(m.name)
    
    ben = Mitarbeiter("Ben", "Entwickler")
    chef = Manager("Nalan", "Teamleitung", [ben])
    chef.team_anzeigen()
  7. 07

    Listen/Dictionaries

    Duplikate, Reverse, zip und Gruppierung — ohne Shortcuts erklärt.

    Offen · 1 Themen
    • Manuelle Listenalgorithmen erklären
    • setdefault für Gruppen
    listzipsetdefault

    7.1–7.4 Listen & Dicts

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: neue Liste / Rückwärts-Index / zip / setdefault. Lösung jeweils kompakt.

    • Lösung: nur anhängen wenn `not in ergebnis`
    • Lösung: `dict(zip(namen, alter))`
    • Lösung: `gruppiert.setdefault(laenge, []).append(w)`

    7.1 Duplikate entfernen ohne `set()` · python

    def ohne_duplikate(liste):
        ergebnis = []
        for element in liste:
            if element not in ergebnis:
                ergebnis.append(element)
        return ergebnis
    
    print(ohne_duplikate([1, 2, 2, 3, 1]))   # [1, 2, 3]

    7.2 Liste umdrehen ohne `.reverse()` · python

    def liste_umdrehen(liste):
        ergebnis = []
        for i in range(len(liste) - 1, -1, -1):
            ergebnis.append(liste[i])
        return ergebnis
    
    print(liste_umdrehen([1, 2, 3]))   # [3, 2, 1]

    7.3 Zwei Listen zu Dictionary · python

    namen = ["Anna", "Ben", "Cem"]
    alter = [25, 30, 22]
    
    personen = dict(zip(namen, alter))
    print(personen)   # {'Anna': 25, 'Ben': 30, 'Cem': 22}

    7.4 Wörter nach Länge gruppieren · python

    woerter = ["Hut", "Apfel", "Bus", "Sonne"]
    
    gruppiert = {}
    for w in woerter:
        laenge = len(w)
        gruppiert.setdefault(laenge, []).append(w)
    
    print(gruppiert)   # {3: ['Hut', 'Bus'], 5: ['Apfel', 'Sonne']}
  8. 08

    Einfache Algorithmen

    Bubble Sort, binäre Suche, Fibonacci, Anagramme, rekursive Fakultät.

    Offen · 1 Themen
    • Algorithmen-Idee vor Code verinnerlichen
    • Basisfall bei Rekursion
    Bubble Sortbinäre SucheRekursion

    8.1–8.5 Algorithmen

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: tauschen / Mitte / Summe der letzten zwei / sorted / Basisfall. Lösung als Funktionen.

    • Vorgehen Bubble: größtes Element „sinkt“ ans Ende
    • Vorgehen binär: nur auf sortierten Listen
    • Lösung Fakultät: `if n == 0: return 1`

    8.1 Bubble Sort · python

    def bubble_sort(liste):
        n = len(liste)
        for i in range(n):
            for j in range(n - i - 1):
                if liste[j] > liste[j + 1]:
                    liste[j], liste[j + 1] = liste[j + 1], liste[j]
        return liste
    
    print(bubble_sort([5, 2, 9, 1, 5]))

    8.2 Binäre Suche · python

    def binaere_suche(liste, ziel):
        links, rechts = 0, len(liste) - 1
        while links <= rechts:
            mitte = (links + rechts) // 2
            if liste[mitte] == ziel:
                return mitte
            elif liste[mitte] < ziel:
                links = mitte + 1
            else:
                rechts = mitte - 1
        return -1
    
    print(binaere_suche([1, 3, 5, 7, 9], 7))   # 3

    8.3 Fibonacci-Folge · python

    def fibonacci(n):
        folge = [0, 1]
        while len(folge) < n:
            folge.append(folge[-1] + folge[-2])
        return folge[:n]
    
    print(fibonacci(8))   # [0, 1, 1, 2, 3, 5, 8, 13]

    8.4 Anagramm prüfen · python

    def sind_anagramme(wort1, wort2):
        return sorted(wort1.lower()) == sorted(wort2.lower())
    
    print(sind_anagramme("Ohr", "Roh"))   # True

    8.5 Fakultät (rekursiv) · python

    def fakultaet(n):
        if n == 0:
            return 1
        return n * fakultaet(n - 1)
    
    print(fakultaet(5))   # 120
  9. 09

    Datenbanken

    sqlite3: CREATE, CRUD mit Platzhaltern und JOIN erklärt.

    Offen · 1 Themen
    • commit und Platzhalter verinnerlichen
    • JOIN über Fremdschlüssel
    sqlite3CRUDJOIN

    9.1–9.5 SQLite

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: connect erstellt Datei; ?-Platzhalter. Lösung: personen-CRUD + bestellungen JOIN.

    • Vorgehen: SQL als String über `.execute()`
    • Lösung: `INSERT … VALUES (?, ?)`
    • Lösung: JOIN personen ↔ bestellungen

    9.1 Datenbank + Tabelle erstellen · python

    import sqlite3
    
    verbindung = sqlite3.connect("datenbank.db")
    cursor = verbindung.cursor()
    
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS personen (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT,
            alter_ INTEGER
        )
    """)
    verbindung.commit()

    9.2 Person hinzufügen · python

    def person_hinzufuegen(name, alter):
        cursor.execute("INSERT INTO personen (name, alter_) VALUES (?, ?)", (name, alter))
        verbindung.commit()
    
    person_hinzufuegen("Nalan", 30)

    9.3 Alle Personen anzeigen · python

    def alle_personen_anzeigen():
        cursor.execute("SELECT * FROM personen")
        for zeile in cursor.fetchall():
            print(zeile)
    
    alle_personen_anzeigen()

    9.4 Löschen & Aktualisieren · python

    def person_loeschen(id):
        cursor.execute("DELETE FROM personen WHERE id = ?", (id,))
        verbindung.commit()
    
    def person_aktualisieren(id, neuer_name):
        cursor.execute("UPDATE personen SET name = ? WHERE id = ?", (neuer_name, id))
        verbindung.commit()

    9.5 Verknüpfte Tabelle mit JOIN · python

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS bestellungen (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            person_id INTEGER,
            produkt TEXT,
            FOREIGN KEY (person_id) REFERENCES personen (id)
        )
    """)
    verbindung.commit()
    
    # Bestellungen einer Person abfragen
    cursor.execute("""
        SELECT personen.name, bestellungen.produkt
        FROM bestellungen
        JOIN personen ON bestellungen.person_id = personen.id
        WHERE personen.id = ?
    """, (1,))
    
    for zeile in cursor.fetchall():
        print(zeile)
  10. 10

    Kleine Webanwendungen (FastAPI)

    Routen, In-Memory/SQLite-Todos, PATCH und fetch-Frontend.

    Offen · 1 Themen
    • FastAPI-Decorator und Pydantic verstehen
    • API mit UI verbinden
    FastAPIPydanticfetch

    10.1–10.5 FastAPI

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: @app.get registriert Route. Lösung: hallo, Todos, SQLite, PATCH, HTML+fetch.

    • Lösung: `return {"message": f"Hallo, {name}!"}`
    • Vorgehen: Liste als Zwischen-DB, dann SQLite
    • Lösung Frontend: `fetch(…).then(…json)`

    10.1 Einfacher Endpunkt · python

    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/hallo/{name}")
    def hallo(name: str):
        return {"message": f"Hallo, {name}!"}
    
    # Starten mit: uvicorn main:app --reload

    10.2 Todo-API (im Speicher) · python

    from fastapi import FastAPI
    from pydantic import BaseModel
    
    app = FastAPI()
    todos = []
    
    class Todo(BaseModel):
        titel: str
        erledigt: bool = False
    
    @app.get("/todos")
    def alle_todos():
        return todos
    
    @app.post("/todos")
    def todo_hinzufuegen(todo: Todo):
        todos.append(todo)
        return {"status": "hinzugefügt"}

    10.3 Mit SQLite verbinden · python

    import sqlite3
    from fastapi import FastAPI
    from pydantic import BaseModel
    
    app = FastAPI()
    
    def get_connection():
        return sqlite3.connect("todos.db")
    
    @app.on_event("startup")
    def setup():
        conn = get_connection()
        conn.execute("""
            CREATE TABLE IF NOT EXISTS todos (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                titel TEXT,
                erledigt INTEGER DEFAULT 0
            )
        """)
        conn.commit()
        conn.close()
    
    class Todo(BaseModel):
        titel: str
    
    @app.post("/todos")
    def todo_hinzufuegen(todo: Todo):
        conn = get_connection()
        conn.execute("INSERT INTO todos (titel) VALUES (?)", (todo.titel,))
        conn.commit()
        conn.close()
        return {"status": "gespeichert"}

    10.4 Als erledigt markieren · python

    @app.patch("/todos/{id}")
    def todo_erledigt(id: int):
        conn = get_connection()
        conn.execute("UPDATE todos SET erledigt = 1 WHERE id = ?", (id,))
        conn.commit()
        conn.close()
        return {"status": "aktualisiert"}

    10.5 Einfaches HTML-Frontend · html

    <div id="liste"></div>
    
    <script>
      fetch("http://localhost:8000/todos")
        .then(response => response.json())
        .then(todos => {
          const container = document.getElementById("liste");
          todos.forEach(todo => {
            const p = document.createElement("p");
            p.textContent = todo.titel;
            container.appendChild(p);
          });
        });
    </script>
  11. 11

    Debugging

    Tracebacks, Print-Debugging, breakpoint und Off-by-one per Lesen.

    Offen · 2 Themen
    • Fehlerquellen systematisch eingrenzen
    • Off-by-one erkennen
    tracebackbreakpointOff-by-one

    11.1–11.4 Debugging

    Lesson · Lösungen · Vorgehen + Lösung

    Vorgehen: Traceback unten lesen; gezielt printen; Debugger; Code simulieren. Beispiele NameError und Bubble-Sort-Range.

    • Vorgehen: letzte Zeile = Fehlertyp
    • Lösung: `breakpoint()` mit `p` / `n` / `c`
    • Lösung: `range(n - i - 1)` statt `range(n - i)`

    11.1 Fehler bewusst einbauen und lesen · python

    def begruessung(nam):   # Tippfehler: sollte 'name' heißen
        return f"Hallo {name}"   # NameError: name 'name' is not defined

    11.2 Print-Debugging · python

    def summe_liste(liste):
        summe = 0
        for zahl in liste:
            print("aktuelle Zahl:", zahl, "| Summe bisher:", summe)   # Debug-Ausgabe
            summe += zahl
        return summe

    11.3 Python-Debugger (`breakpoint()`) · python

    def berechne(a, b):
        ergebnis = a * b
        breakpoint()   # Programm hält hier an
        return ergebnis + 10
    
    berechne(3, 4)

    11.4 Fehler nur durch Lesen finden · python

    def bubble_sort(liste):
        n = len(liste)
        for i in range(n):
            for j in range(n - i):        # Fehler: sollte range(n - i - 1) sein
                if liste[j] > liste[j + 1]:   # → IndexError bei letztem Durchlauf
                    liste[j], liste[j + 1] = liste[j + 1], liste[j]
        return liste

Vollständige Anleitung

Python Lösungen – Schritt für Schritt erklärt

Alle Abschnitte und Code-Beispiele aus der Quelle — auch als Lektion oder PDF.

Python Lösungen – Schritt für Schritt erklärt

Zu jeder Aufgabe: Vorgehen (wie du drangehst) + Lösung (Code). Tipp: Lies erst nur "Vorgehen", versuch es nochmal selbst, und schau erst danach in die Lösung.


1. Kleine Python-Programme

1.1 Nutzer begrüßen

Vorgehen: Eingabe mit input() holen, in Variable speichern, mit f-String ausgeben.

name = input("Wie heißt du? ")
print(f"Hallo {name}, schön dich kennenzulernen!")

1.2 Taschenrechner

Vorgehen: Zwei Zahlen + Operator einlesen (Achtung: input() liefert immer Text → mit float() umwandeln). Dann mit if/elif die passende Rechenart auswählen.

a = float(input("Erste Zahl: "))
b = float(input("Zweite Zahl: "))
op = input("Rechenart (+,-,*,/): ")

if op == "+":
    print(a + b)
elif op == "-":
    print(a - b)
elif op == "*":
    print(a * b)
elif op == "/":
    if b != 0:
        print(a / b)
    else:
        print("Division durch 0 nicht möglich")
else:
    print("Unbekannte Rechenart")

1.3 Primzahl prüfen

Vorgehen: Eine Zahl ist prim, wenn sie nur durch 1 und sich selbst teilbar ist. Prüfe alle Zahlen von 2 bis zahl-1 (oder bis zur Wurzel, effizienter). Wenn eine davon ohne Rest teilt → keine Primzahl.

def ist_primzahl(zahl):
    if zahl < 2:
        return False
    for i in range(2, zahl):
        if zahl % i == 0:
            return False
    return True

print(ist_primzahl(7))   # True
print(ist_primzahl(8))   # False

1.4 Zahlen erraten

Vorgehen: Zufallszahl mit random.randint() erzeugen. In einer while True-Schleife raten lassen, vergleichen, Hinweis geben, bei Treffer mit break beenden.

import random

zielzahl = random.randint(1, 100)

while True:
    versuch = int(input("Rate eine Zahl (1-100): "))
    if versuch < zielzahl:
        print("Höher!")
    elif versuch > zielzahl:
        print("Niedriger!")
    else:
        print("Richtig!")
        break

2. APIs

2.1 Nutzer von JSONPlaceholder holen

Vorgehen: requests.get(url) sendet die Anfrage. .json() wandelt die Antwort in Python-Datenstruktur (Liste von Dicts) um. Dann normal durchiterieren.

import requests

response = requests.get("https://jsonplaceholder.typicode.com/users")
users = response.json()

for user in users:
    print(user["name"])

2.2 Wetterdaten (Open-Meteo, kein API-Key nötig)

Vorgehen: URL mit Koordinaten aufrufen, JSON auslesen. Prüfe die API-Doku für die genauen Feldnamen der Antwort.

import requests

lat, lon = 53.0793, 8.8017  # Bremen
url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&current_weather=true"

response = requests.get(url)
data = response.json()

temperatur = data["current_weather"]["temperature"]
print(f"Aktuelle Temperatur: {temperatur}°C")

2.3 Zufallswitz-Funktion

Vorgehen: Funktion kapselt den API-Aufruf, damit man sie wiederverwenden kann. Setup + Punchline liegen als eigene Felder in der Antwort.

import requests

def hole_zufallswitz():
    response = requests.get("https://official-joke-api.appspot.com/random_joke")
    witz = response.json()
    return f"{witz['setup']} — {witz['punchline']}"

print(hole_zufallswitz())

2.4 API-Daten zusätzlich lokal speichern

Vorgehen: Ergebnis von .json() ist bereits eine Python-Liste/Dict → direkt mit json.dump() in Datei schreiben.

import requests
import json

response = requests.get("https://jsonplaceholder.typicode.com/users")
users = response.json()

with open("users.json", "w") as f:
    json.dump(users, f, indent=2)

print("Gespeichert!")

3. Daten verarbeiten

3.1 Summe, Durchschnitt, Min, Max ohne eingebaute Funktionen

Vorgehen: Mit einer Schleife durchlaufen, laufend vergleichen/addieren – wie die eingebauten Funktionen intern arbeiten.

zahlen = [4, 8, 2, 9, 5]

summe = 0
minimum = zahlen[0]
maximum = zahlen[0]

for z in zahlen:
    summe += z
    if z < minimum:
        minimum = z
    if z > maximum:
        maximum = z

durchschnitt = summe / len(zahlen)
print(summe, durchschnitt, minimum, maximum)

3.2 Längstes Wort + Anfangsbuchstaben zählen

Vorgehen: Längstes Wort: laufend vergleichen wie bei Max oben. Für die Zählung: Dictionary nutzen, .get(key, 0) um sicher hochzuzählen ohne KeyError.

woerter = ["Apfel", "Birne", "Ananas", "Kiwi"]

laengstes = woerter[0]
for w in woerter:
    if len(w) > len(laengstes):
        laengstes = w
print("Längstes Wort:", laengstes)

buchstaben_count = {}
for w in woerter:
    erster = w[0]
    buchstaben_count[erster] = buchstaben_count.get(erster, 0) + 1

print(buchstaben_count)

3.3 Produkte filtern & sortieren

Vorgehen: List Comprehension zum Filtern, sorted() mit key= um nach einem bestimmten Feld zu sortieren.

produkte = [
    {"name": "Kette", "preis": 25},
    {"name": "Ring", "preis": 60},
    {"name": "Armband", "preis": 45},
]

teure_produkte = [p for p in produkte if p["preis"] > 50]
sortiert = sorted(produkte, key=lambda p: p["preis"])

print(teure_produkte)
print(sortiert)

3.4 CSV einlesen & Umsatz berechnen

Vorgehen: csv.DictReader liest jede Zeile als Dictionary (Spaltennamen = Keys). Werte aus CSV sind immer Strings → für Berechnungen umwandeln.

import csv

umsatz_pro_produkt = {}

with open("verkaeufe.csv", newline="") as f:
    reader = csv.DictReader(f)
    for zeile in reader:
        produkt = zeile["Produkt"]
        menge = int(zeile["Menge"])
        preis = float(zeile["Preis"])
        umsatz = menge * preis
        umsatz_pro_produkt[produkt] = umsatz_pro_produkt.get(produkt, 0) + umsatz

print(umsatz_pro_produkt)

4. Dateien lesen/schreiben

4.1 Text in Datei schreiben

Vorgehen: open() mit Modus "w" (write) – überschreibt die Datei. with sorgt dafür, dass die Datei automatisch geschlossen wird.

def notiz_schreiben(text):
    with open("notizen.txt", "w") as f:
        f.write(text)

notiz_schreiben("Meine erste Notiz")

4.2 Datei zeilenweise lesen

Vorgehen: Modus "r" (read). Über die geöffnete Datei kann man direkt mit for iterieren, jede Zeile ist ein String.

def notiz_lesen():
    with open("notizen.txt", "r") as f:
        for zeile in f:
            print(zeile.strip())   # strip() entfernt den Zeilenumbruch

notiz_lesen()

4.3 Tagebuch mit Anhängen

Vorgehen: Modus "a" (append) fügt hinzu statt zu überschreiben. datetime für den Zeitstempel.

from datetime import datetime

def eintrag_hinzufuegen(text):
    zeitstempel = datetime.now().strftime("%Y-%m-%d %H:%M")
    with open("tagebuch.txt", "a") as f:
        f.write(f"[{zeitstempel}] {text}\n")

eintrag_hinzufuegen("Heute Python geübt.")

4.4 JSON schreiben & lesen

Vorgehen: json.dump() schreibt eine Python-Struktur als JSON-Datei, json.load() liest sie zurück in eine Python-Struktur.

import json

personen = [{"name": "Anna", "alter": 25}, {"name": "Ben", "alter": 30}]

with open("personen.json", "w") as f:
    json.dump(personen, f, indent=2)

with open("personen.json", "r") as f:
    geladen = json.load(f)

print(geladen)

5. Fehlerbehandlung

5.1 Erneut fragen bei ungültiger Zahl

Vorgehen: while True + try/except ValueError. Bei Erfolg mit break raus, bei Fehler Meldung + Schleife läuft weiter.

while True:
    try:
        zahl = int(input("Gib eine Zahl ein: "))
        break
    except ValueError:
        print("Das ist keine gültige Zahl, versuch's nochmal.")

print("Du hast eingegeben:", zahl)

5.2 Sichere Division

Vorgehen: try/except ZeroDivisionError gezielt für den einen Fehlerfall, den wir erwarten.

def sichere_division(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return "Fehler: Division durch 0 nicht möglich"

print(sichere_division(10, 2))
print(sichere_division(10, 0))

5.3 Datei-Fehler abfangen

Vorgehen: FileNotFoundError ist eine eigene, spezifischere Exception-Klasse – gezielt abfangen statt generisches except Exception.

try:
    with open("nicht_vorhanden.txt") as f:
        inhalt = f.read()
except FileNotFoundError:
    print("Die Datei wurde nicht gefunden.")

5.4 Eigene Exception-Klasse

Vorgehen: Eigene Exceptions erben von Exception. Mit raise wirfst du sie selbst, wenn eine Bedingung verletzt ist.

class UngueltigesAlterError(Exception):
    pass

def alter_setzen(alter):
    if alter < 0:
        raise UngueltigesAlterError("Alter darf nicht negativ sein")
    return alter

try:
    alter_setzen(-5)
except UngueltigesAlterError as e:
    print("Fehler:", e)

6. Funktionen und Klassen

6.1 Palindrom prüfen

Vorgehen: String umgedreht ([::-1]) mit Original vergleichen.

def ist_palindrom(text):
    text = text.lower()
    return text == text[::-1]

print(ist_palindrom("anna"))    # True
print(ist_palindrom("hallo"))   # False

6.2 Klasse Auto mit Altersberechnung

Vorgehen: Aktuelles Jahr über datetime.now().year holen, dann simple Subtraktion in einer Methode.

from datetime import datetime

class Auto:
    def __init__(self, marke, baujahr):
        self.marke = marke
        self.baujahr = baujahr

    def alter(self):
        return datetime.now().year - self.baujahr

mein_auto = Auto("BMW", 2018)
print(mein_auto.alter())

6.3 Klasse Warenkorb

Vorgehen: Liste als Attribut im Konstruktor anlegen. Methoden verändern diese Liste (append, remove) bzw. berechnen daraus (sum() über Preise).

class Warenkorb:
    def __init__(self):
        self.produkte = []

    def hinzufuegen(self, name, preis):
        self.produkte.append({"name": name, "preis": preis})

    def entfernen(self, name):
        self.produkte = [p for p in self.produkte if p["name"] != name]

    def gesamtpreis(self):
        return sum(p["preis"] for p in self.produkte)

korb = Warenkorb()
korb.hinzufuegen("Kette", 25)
korb.hinzufuegen("Ring", 40)
print(korb.gesamtpreis())   # 65

6.4 Vererbung: Mitarbeiter → Manager

Vorgehen: Manager erbt von Mitarbeiter mit class Manager(Mitarbeiter):. super().__init__() ruft den Konstruktor der Basisklasse auf, um Code nicht zu duplizieren.

class Mitarbeiter:
    def __init__(self, name, position):
        self.name = name
        self.position = position

class Manager(Mitarbeiter):
    def __init__(self, name, position, team):
        super().__init__(name, position)
        self.team = team   # Liste von Mitarbeiter-Objekten

    def team_anzeigen(self):
        for m in self.team:
            print(m.name)

ben = Mitarbeiter("Ben", "Entwickler")
chef = Manager("Nalan", "Teamleitung", [ben])
chef.team_anzeigen()

7. Listen/Dictionaries

7.1 Duplikate entfernen ohne set()

Vorgehen: Neue leere Liste, jedes Element nur hinzufügen, wenn es noch nicht drin ist.

def ohne_duplikate(liste):
    ergebnis = []
    for element in liste:
        if element not in ergebnis:
            ergebnis.append(element)
    return ergebnis

print(ohne_duplikate([1, 2, 2, 3, 1]))   # [1, 2, 3]

7.2 Liste umdrehen ohne .reverse()

Vorgehen: Rückwärts durch die Originalliste iterieren (Index von hinten) und in neue Liste anhängen.

def liste_umdrehen(liste):
    ergebnis = []
    for i in range(len(liste) - 1, -1, -1):
        ergebnis.append(liste[i])
    return ergebnis

print(liste_umdrehen([1, 2, 3]))   # [3, 2, 1]

7.3 Zwei Listen zu Dictionary

Vorgehen: zip() kombiniert zwei Listen elementweise zu Paaren, dict() wandelt das direkt in ein Dictionary um.

namen = ["Anna", "Ben", "Cem"]
alter = [25, 30, 22]

personen = dict(zip(namen, alter))
print(personen)   # {'Anna': 25, 'Ben': 30, 'Cem': 22}

7.4 Wörter nach Länge gruppieren

Vorgehen: Für jedes Wort die Länge als Key nutzen, mit .setdefault() eine leere Liste anlegen falls noch nicht vorhanden, dann anhängen.

woerter = ["Hut", "Apfel", "Bus", "Sonne"]

gruppiert = {}
for w in woerter:
    laenge = len(w)
    gruppiert.setdefault(laenge, []).append(w)

print(gruppiert)   # {3: ['Hut', 'Bus'], 5: ['Apfel', 'Sonne']}

8. Einfache Algorithmen

8.1 Bubble Sort

Vorgehen: Wiederholt benachbarte Elemente vergleichen und tauschen, wenn sie in falscher Reihenfolge sind. Nach jedem Durchlauf "sinkt" das größte verbleibende Element ans Ende.

def bubble_sort(liste):
    n = len(liste)
    for i in range(n):
        for j in range(n - i - 1):
            if liste[j] > liste[j + 1]:
                liste[j], liste[j + 1] = liste[j + 1], liste[j]
    return liste

print(bubble_sort([5, 2, 9, 1, 5]))

8.2 Binäre Suche

Vorgehen: Nur auf sortierten Listen. Immer die Mitte prüfen, dann je nach Vergleich nur noch die linke oder rechte Hälfte weiter durchsuchen.

def binaere_suche(liste, ziel):
    links, rechts = 0, len(liste) - 1
    while links <= rechts:
        mitte = (links + rechts) // 2
        if liste[mitte] == ziel:
            return mitte
        elif liste[mitte] < ziel:
            links = mitte + 1
        else:
            rechts = mitte - 1
    return -1

print(binaere_suche([1, 3, 5, 7, 9], 7))   # 3

8.3 Fibonacci-Folge

Vorgehen: Start mit den ersten zwei Werten (0, 1), jede weitere Zahl ist die Summe der letzten zwei.

def fibonacci(n):
    folge = [0, 1]
    while len(folge) < n:
        folge.append(folge[-1] + folge[-2])
    return folge[:n]

print(fibonacci(8))   # [0, 1, 1, 2, 3, 5, 8, 13]

8.4 Anagramm prüfen

Vorgehen: Zwei Wörter sind Anagramme, wenn sie – sortiert – identisch sind.

def sind_anagramme(wort1, wort2):
    return sorted(wort1.lower()) == sorted(wort2.lower())

print(sind_anagramme("Ohr", "Roh"))   # True

8.5 Fakultät (rekursiv)

Vorgehen: Rekursion braucht einen Basisfall (hier: 0! = 1), sonst läuft sie endlos. Jeder Aufruf ruft sich selbst mit kleinerem Wert auf, bis der Basisfall erreicht ist.

def fakultaet(n):
    if n == 0:
        return 1
    return n * fakultaet(n - 1)

print(fakultaet(5))   # 120

9. Datenbanken (SQLite)

9.1 Datenbank + Tabelle erstellen

Vorgehen: sqlite3.connect() erstellt die Datei automatisch, falls sie nicht existiert. SQL-Befehle werden als String über .execute() gesendet.

import sqlite3

verbindung = sqlite3.connect("datenbank.db")
cursor = verbindung.cursor()

cursor.execute("""
    CREATE TABLE IF NOT EXISTS personen (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        alter_ INTEGER
    )
""")
verbindung.commit()

9.2 Person hinzufügen

Vorgehen: ?-Platzhalter statt Werte direkt in den String einzufügen (verhindert SQL-Injection). Nach INSERT immer commit() nicht vergessen.

def person_hinzufuegen(name, alter):
    cursor.execute("INSERT INTO personen (name, alter_) VALUES (?, ?)", (name, alter))
    verbindung.commit()

person_hinzufuegen("Nalan", 30)

9.3 Alle Personen anzeigen

Vorgehen: SELECT liefert die Daten, .fetchall() holt alle Ergebniszeilen als Liste von Tupeln.

def alle_personen_anzeigen():
    cursor.execute("SELECT * FROM personen")
    for zeile in cursor.fetchall():
        print(zeile)

alle_personen_anzeigen()

9.4 Löschen & Aktualisieren

def person_loeschen(id):
    cursor.execute("DELETE FROM personen WHERE id = ?", (id,))
    verbindung.commit()

def person_aktualisieren(id, neuer_name):
    cursor.execute("UPDATE personen SET name = ? WHERE id = ?", (neuer_name, id))
    verbindung.commit()

9.5 Verknüpfte Tabelle mit JOIN

Vorgehen: Fremdschlüssel = Spalte, die auf die id einer anderen Tabelle verweist. JOIN verbindet beide Tabellen über diese Spalte.

cursor.execute("""
    CREATE TABLE IF NOT EXISTS bestellungen (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        person_id INTEGER,
        produkt TEXT,
        FOREIGN KEY (person_id) REFERENCES personen (id)
    )
""")
verbindung.commit()

# Bestellungen einer Person abfragen
cursor.execute("""
    SELECT personen.name, bestellungen.produkt
    FROM bestellungen
    JOIN personen ON bestellungen.person_id = personen.id
    WHERE personen.id = ?
""", (1,))

for zeile in cursor.fetchall():
    print(zeile)

10. Kleine Webanwendungen (FastAPI)

10.1 Einfacher Endpunkt

Vorgehen: @app.get("/pfad") registriert eine Route. Die Funktion darunter läuft, wenn diese URL aufgerufen wird. Rückgabe wird automatisch zu JSON.

from fastapi import FastAPI

app = FastAPI()

@app.get("/hallo/{name}")
def hallo(name: str):
    return {"message": f"Hallo, {name}!"}

# Starten mit: uvicorn main:app --reload

10.2 Todo-API (im Speicher)

Vorgehen: Einfache Python-Liste als "Datenbank-Ersatz". POST nimmt Daten über den Request-Body entgegen (mit Pydantic-Modell definiert).

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()
todos = []

class Todo(BaseModel):
    titel: str
    erledigt: bool = False

@app.get("/todos")
def alle_todos():
    return todos

@app.post("/todos")
def todo_hinzufuegen(todo: Todo):
    todos.append(todo)
    return {"status": "hinzugefügt"}

10.3 Mit SQLite verbinden

Vorgehen: Statt der Liste todos nutzt du die Funktionen aus Aufgabe 9 (mit einer todos-Tabelle statt personen), um bei jedem Request in die Datenbank zu schreiben/lesen.

import sqlite3
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

def get_connection():
    return sqlite3.connect("todos.db")

@app.on_event("startup")
def setup():
    conn = get_connection()
    conn.execute("""
        CREATE TABLE IF NOT EXISTS todos (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            titel TEXT,
            erledigt INTEGER DEFAULT 0
        )
    """)
    conn.commit()
    conn.close()

class Todo(BaseModel):
    titel: str

@app.post("/todos")
def todo_hinzufuegen(todo: Todo):
    conn = get_connection()
    conn.execute("INSERT INTO todos (titel) VALUES (?)", (todo.titel,))
    conn.commit()
    conn.close()
    return {"status": "gespeichert"}

10.4 Als erledigt markieren

Vorgehen: PATCH/PUT mit der id als URL-Parameter, UPDATE-Statement in der Datenbank.

@app.patch("/todos/{id}")
def todo_erledigt(id: int):
    conn = get_connection()
    conn.execute("UPDATE todos SET erledigt = 1 WHERE id = ?", (id,))
    conn.commit()
    conn.close()
    return {"status": "aktualisiert"}

10.5 Einfaches HTML-Frontend

Vorgehen: fetch() im Browser ruft deine FastAPI-Endpunkte auf, .json() verarbeitet die Antwort, .map()/Schleife baut daraus HTML.

<div id="liste"></div>

<script>
  fetch("http://localhost:8000/todos")
    .then(response => response.json())
    .then(todos => {
      const container = document.getElementById("liste");
      todos.forEach(todo => {
        const p = document.createElement("p");
        p.textContent = todo.titel;
        container.appendChild(p);
      });
    });
</script>

11. Debugging

11.1 Fehler bewusst einbauen und lesen

Vorgehen: Python-Fehlermeldungen lesen sich von unten nach oben: die letzte Zeile sagt dir den Fehlertyp + was genau falsch ist, die Zeilen darüber zeigen dir wo im Code (Traceback).

def begruessung(nam):   # Tippfehler: sollte 'name' heißen
    return f"Hallo {name}"   # NameError: name 'name' is not defined

→ Die Fehlermeldung nennt exakt Zeile und Variable. Erste Anlaufstelle bei jedem Fehler.

11.2 Print-Debugging

Vorgehen: Gezielt an "verdächtigen" Stellen den Wert einer Variable ausgeben, um zu sehen, ob sie das enthält, was du erwartest.

def summe_liste(liste):
    summe = 0
    for zahl in liste:
        print("aktuelle Zahl:", zahl, "| Summe bisher:", summe)   # Debug-Ausgabe
        summe += zahl
    return summe

11.3 Python-Debugger (breakpoint())

Vorgehen: breakpoint() pausiert das Programm an genau dieser Stelle. Im Terminal kannst du dann interaktiv Variablen inspizieren.

def berechne(a, b):
    ergebnis = a * b
    breakpoint()   # Programm hält hier an
    return ergebnis + 10

berechne(3, 4)

Im Debugger-Prompt: p ergebnis (Wert anzeigen), n (nächste Zeile), c (weiterlaufen lassen).

11.4 Fehler nur durch Lesen finden

Vorgehen: Code Zeile für Zeile durchgehen und mit Papier/Kopf "simulieren", welchen Wert jede Variable zu jedem Zeitpunkt hat – ohne ihn auszuführen.

def bubble_sort(liste):
    n = len(liste)
    for i in range(n):
        for j in range(n - i):        # Fehler: sollte range(n - i - 1) sein
            if liste[j] > liste[j + 1]:   # → IndexError bei letztem Durchlauf
                liste[j], liste[j + 1] = liste[j + 1], liste[j]
    return liste

→ Bei j = n - i - 1 (letzter Wert der Range) wird auf liste[j + 1] zugegriffen, was aber außerhalb der Liste liegt. Klassischer Off-by-one-Fehler.


Merksatz zum Vorgehen bei jeder neuen Aufgabe

  1. Verstehen: Was soll am Ende rauskommen? (Beispiel-Input/Output aufschreiben)
  2. Zerlegen: In welche kleineren Schritte lässt sich das aufteilen?
  3. Grob skizzieren: Pseudocode oder Kommentare für jeden Schritt
  4. Schritt für Schritt coden und nach jedem Schritt mit print() testen
  5. Erst am Ende auf saubere/kurze Lösung optimieren

Wenn du bei einer der Lösungen etwas nicht verstehst oder es lieber gemeinsam nochmal Zeile für Zeile durchgehen willst, sag einfach welche.