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}¤t_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
- Verstehen: Was soll am Ende rauskommen? (Beispiel-Input/Output aufschreiben)
- Zerlegen: In welche kleineren Schritte lässt sich das aufteilen?
- Grob skizzieren: Pseudocode oder Kommentare für jeden Schritt
- Schritt für Schritt coden und nach jedem Schritt mit
print()testen - 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.