Collections: Kurzeinführung

Diese Kurzeinführung erläutert die Grundlagen von Collections in Python und dient zur Unterstützung bei der Bearbeitung der Übungsaufgaben. Ein entsprechendes Short-Video wird noch bereitgestellt.

Von C zu Python Collections

Wenn Sie bereits mit Arrays in C vertraut sind, werden Sie feststellen, dass Python Collections deutlich flexibler sind. Anders als in C müssen Sie sich keine Gedanken über Speicherverwaltung machen - Python übernimmt das für Sie.

Listen: Die flexiblen Arrays

# In C:
int noten[100];    // Feste Größe festlegen
noten[0] = 95;     // Elementen zuweisen

# In Python:
noten = []         # Leere Liste erstellen
noten.append(95)   # Element hinzufügen - Liste wächst automatisch
noten.append(87)
print(noten)       # Ausgabe: [95, 87]

Listen sind die vielseitigste Collection in Python. Sie können:

  • Dynamisch wachsen und schrumpfen
  • Verschiedene Datentypen mischen
  • Einfach durchsucht und verändert werden

Grundlegende Listenoperationen

# Liste erstellen
zahlen = [1, 2, 3, 4, 5]

# Elemente hinzufügen
zahlen.append(6)        # Am Ende: [1, 2, 3, 4, 5, 6]
zahlen.insert(0, 0)     # Am Anfang: [0, 1, 2, 3, 4, 5, 6]

# Auf Elemente zugreifen
erstes = zahlen[0]      # Erstes Element
letztes = zahlen[-1]    # Letztes Element

# Länge der Liste
laenge = len(zahlen)    # 7

# Elemente entfernen
zahlen.remove(3)        # Entfernt die erste 3
del zahlen[0]           # Entfernt das erste Element

Listen in Funktionen

Ein wichtiger Unterschied zu C: Wenn Sie eine Liste an eine Funktion übergeben, wird sie nicht kopiert. Änderungen in der Funktion wirken sich auf die ursprüngliche Liste aus.

def add_note(noten_liste, note):
    noten_liste.append(note)    # Ändert die originale Liste!

meine_noten = [95, 87, 92]
add_note(meine_noten, 89)
print(meine_noten)             # [95, 87, 92, 89]

# Wenn Sie die Liste nicht ändern wollen:
def add_note_safe(noten_liste, note):
    neue_liste = list(noten_liste)  # Erstellt eine Kopie
    neue_liste.append(note)
    return neue_liste

meine_noten = [95, 87, 92]
neue_noten = add_note_safe(meine_noten, 89)
print(meine_noten)   # Original unverändert: [95, 87, 92]
print(neue_noten)    # Neue Liste: [95, 87, 92, 89]

Dieser grundlegende Unterschied zu C - dass Funktionsparameter sich auf das Original auswirken können - führt uns zu einem wichtigen Konzept in Python: Mutable (veränderbare) und Immutable (unveränderliche) Objekte.

Mutable und Immutable Objekte

In Python gibt es zwei Arten von Objekten:

  • Mutable (veränderbar): Listen, Dictionaries, Sets
  • Immutable (unveränderlich): Zahlen, Strings, Tupel

Beispiel mit Strings

# Strings sind immutable
text = "Hello"
text[0] = "J"  # Fehler! Strings können nicht geändert werden

# Stattdessen: Neuen String erstellen
text = "J" + text[1:]  # Ergibt "Jello"

Tupel: Die unveränderliche Liste

Tupel sind wie Listen, aber immutable. Sie werden mit runden Klammern erstellt:

# Tupel erstellen
koordinaten = (3, 4)
punkt = 3, 4      # Klammern sind optional

# Zugriff wie bei Listen
x = koordinaten[0]    # 3

# Aber keine Änderungen möglich
# koordinaten[0] = 5  # Fehler!

Tupel sind besonders nützlich für:

  1. Mehrere Rückgabewerte aus Funktionen:
def get_position():
    return (100, 200)

x, y = get_position()  # Automatisches Entpacken
  1. Schnelles Vertauschen von Variablen:
a = 5
b = 10
a, b = b, a  # Elegant tauschen mit Tupel

Dictionaries: Schlüssel-Wert Paare

Dictionaries verbinden Schlüssel (Keys) mit Werten (Values). Sie sind wie eine Art Nachschlagewerk:

# Dictionary erstellen
noten = {
    "Alice": 95,
    "Bob": 87,
    "Charlie": 92
}

# Zugriff und Änderung
print(noten["Alice"])       # 95
noten["David"] = 89         # Neuen Eintrag hinzufügen

# Sicherer Zugriff
note = noten.get("Eve", 0)  # 0 wenn "Eve" nicht existiert

# Über Dictionary iterieren
for name, note in noten.items():
    print(f"{name}: {note}")

Wichtig: Dictionary-Schlüssel müssen immutable sein. Daher können wir Strings und Tupel als Schlüssel verwenden, aber keine Listen:

# Geht nicht:
d = {[1, 2]: "Liste als Schlüssel"}   # Fehler!

# Geht:
d = {(1, 2): "Tupel als Schlüssel"}   # OK
d = {"name": "String als Schlüssel"}  # OK

Sets: Mengen eindeutiger Elemente

Sets sind Sammlungen ohne Duplikate. Sie sind perfekt zum Entfernen von Mehrfacheinträgen:

# Set erstellen
zahlen = {1, 2, 3, 2, 1}  # Duplikate werden automatisch entfernt
print(zahlen)             # {1, 2, 3}

# Liste mit Duplikaten zu Set konvertieren
namen = ["Alice", "Bob", "Alice", "Charlie"]
unique_namen = set(namen)
print(unique_namen)       # {'Alice', 'Bob', 'Charlie'}

# Mengenoperationen
team_a = {"Alice", "Bob", "Charlie"}
team_b = {"Bob", "David", "Eve"}
gemeinsam = team_a & team_b    # Schnittmenge
nur_a = team_a - team_b        # Differenz
alle = team_a | team_b         # Vereinigung

Geschachtelte Collections

Collections können andere Collections enthalten. Das ermöglicht komplexe Datenstrukturen:

Mehrdimensionale Strukturen

# 2D-Liste (wie 2D-Array in C)
schachbrett = [
    ['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'],
    ['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    ['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
    ['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r']
]

# Zugriff auf einzelne Felder
print(schachbrett[0][0])  # 'R' (obere linke Ecke)

Strukturierte Daten mit Dictionaries

# Komplexe Kursdaten
kurse = {
    "Python": {
        "teilnehmer": [
            {"name": "Alice", "note": 95},
            {"name": "Bob", "note": 87}
        ],
        "raum": "A101",
        "zeiten": ["Mo 14:00", "Mi 16:00"]
    },
    "Java": {
        "teilnehmer": [
            {"name": "Charlie", "note": 92},
            {"name": "David", "note": 88}
        ],
        "raum": "B205",
        "zeiten": ["Di 10:00", "Do 10:00"]
    }
}

# Gezielter Zugriff
print(kurse["Python"]["teilnehmer"][0]["note"])  # 95

# Iteration über verschachtelte Strukturen
for kurs, info in kurse.items():
    print(f"\nKurs: {kurs}")
    print(f"Raum: {info['raum']}")
    for student in info['teilnehmer']:
        print(f"- {student['name']}: {student['note']}")

Praktische Muster und Tipps

Sicherer Dictionary-Zugriff

# Vermeiden Sie KeyError
kurs = "C++"
if kurs in kurse:
    print(kurse[kurs])
else:
    print("Kurs nicht gefunden")

# Oder mit get()
info = kurse.get(kurs, {"teilnehmer": [], "raum": "N/A"})

Referenzen vs. Kopien

Achtung – in Python arbeitet man immer mit einer Referenz auf ein Objekt. Objekte sind in der Regel veränderlich (mutable). Ausnahmen sind Immutables wie Zahlen, Strings und Tupel – nur bei diesen Objekten wird beim Zuweisen bzw. Ändern automatisch ein neues Objekt erzeugt.

# Liste kopieren
a = [1, 2, 3]
b = a           # b ist nur eine Referenz auf a
b[0] = 99
print(a[0])     # Ist jetzt auch 99!

# Richtig kopieren
b = list(a)     # Flache Kopie
b = a.copy()    # Alternative flache Kopie

Zusammenfassung

  • Listen für geordnete, veränderbare Sequenzen
  • Tupel für unveränderbare Wertgruppen
  • Dictionaries für Schlüssel-Wert-Zuordnungen
  • Sets für eindeutige Werte und Mengenoperationen
  • Bei verschachtelten Strukturen auf Übersichtlichkeit achten
  • Vorsicht bei Referenzen und Kopien