AF1: Immutable Values erläutern

Ich kann das Konzept von immutable values erläutern und dazu Beispiele anwenden. Somit kann ich dieses Konzept funktionaler Programmierung im Unterschied zu anderen Programmiersprachen erklären (z.Bsp. im Vergleich zu referenzierten Objekten).

Lernziele

# Lernziel Beantwortet in
1 Ich kann erklären, was Immutability bedeutet, und an einem Python-Beispiel zeigen, wie immutable Werte funktionieren. Was ist Immutability?
2 Ich kann anhand eines Codebeispiels erklären, warum referenzierte Objekte in Python problematisch sein können und wie Immutability dieses Problem löst. Das Aliasing-Problem
3 Ich kann in gegebenem Code erkennen, ob eine Mutation vorliegt, und die funktionale Alternative zeigen. Das Aliasing-Problem

Was ist Immutability?

Immutability bedeutet, dass ein Wert nach seiner Erstellung nicht mehr verändert werden kann. Statt einen bestehenden Wert zu ändern, erstellt man einen neuen.

Immutability in Python

Python bietet mehrere immutable Typen:

Typ Beschreibung Beispiel
tuple Unveränderbare Liste (1, 2, 3)
frozenset Unveränderbare Menge frozenset([1, 2, 3])
str Strings sind immer immutable "hello".upper() erzeugt einen neuen String
Zahltypen int, float sind immutable x = 5 kann nicht verändert werden

Beispiel: tuple vs. list

# Immutable: tuple hat keine Änderungsmethoden
items = (1, 2, 3)
# items[0] = 99  # TypeError! Kann nicht verändert werden.

# Mutable: list kann verändert werden
items = [1, 2, 3]
items[0] = 99  # Erlaubt, aber potentiell gefährlich: das Original wird verändert.

Bei einem tuple erzwingt Python die Unveränderlichkeit. Man kann das Objekt nach der Erstellung nicht mehr verändern.

Unveränderbare Collections

# Immutable: tuple("...") erzeugt einen neuen String
text = "hello"
text_neu = text.upper()
print(text)      # "hello" - Original unverändert
print(text_neu)  # "HELLO"

# List mit Kopie arbeiten statt zu mutieren
numbers = [1, 2, 3]
more_numbers = numbers + [4]  # Neue Liste statt Mutation
print(numbers)      # [1, 2, 3]
print(more_numbers) # [1, 2, 3, 4]

Mutable vs. Immutable in Python

Mutable (veränderbar) Immutable (unveränderbar)
list tuple
dict frozenset
set str

Vergleich im Code

# Mutable: Liste wird direkt verändert
numbers = [1, 2, 3]
numbers.append(4)       # numbers ist jetzt [1, 2, 3, 4]
print(numbers) # => [1, 2, 3, 4]

# Immutable: String kann nicht verändert werden
text = "hello"
text_upper = text.upper() # Erstellt einen neuen String
print(text)         # => "hello" (Original unverändert)
print(text_upper)   # => "HELLO"

Vorteile von Immutability

Vorteil Erklärung
Vorhersagbarkeit Wenn sich Werte nie ändern, gibt es keine Überraschungen.
Thread-Sicherheit Unveränderbare Daten können ohne Locks parallel gelesen werden.
Einfacheres Debugging Man muss nicht suchen, wo ein Wert ungewollt geändert wurde.
Performance Unveränderbare Objekte können einfacher optimiert werden.

Das Aliasing-Problem

In Python zeigen Variablen auf dasselbe Objekt im Speicher (Referenzsemantik). Wenn mehrere Variablen auf dasselbe Objekt zeigen, kann eine Änderung über eine Variable alle anderen unbeabsichtigt beeinflussen.

Das Problem in Aktion

original = [1, 2, 3]
copy = original  # Keine echte Kopie, nur eine zweite Referenz!

copy.append(4)

print(original) # => [1, 2, 3, 4]  (unbeabsichtigt verändert!)
print(copy)     # => [1, 2, 3, 4]

Beide Variablen zeigen auf dieselbe Liste. Eine Änderung über copy betrifft auch original.

Konkretes Beispiel: Warenkorb

# Problematisch: verändert die originale Liste
def add_item(cart: list, item: str) -> list:
    cart.append(item)
    return cart

warenkorb = ["Brot", "Milch"]
neuer_warenkorb = add_item(warenkorb, "Käse")

print(warenkorb)       # => ["Brot", "Milch", "Käse"]  (ungewollt verändert!)
print(neuer_warenkorb) # => ["Brot", "Milch", "Käse"]

Funktionale Lösung mit Immutability

# Funktional: erstellt eine neue Liste, Original bleibt unverändert
def add_item(cart: list, item: str) -> list:
    return cart + [item]

warenkorb = ["Brot", "Milch"]
neuer_warenkorb = add_item(warenkorb, "Käse")

print(warenkorb)       # => ["Brot", "Milch"]  (unverändert!)
print(neuer_warenkorb) # => ["Brot", "Milch", "Käse"]

cart + [item] erzeugt eine neue, unveränderbare Liste. Das Original bleibt unangetastet. Genau das ist das Prinzip der funktionalen Programmierung: statt Daten zu verändern, neue Werte erzeugen. In Python wird dieses Prinzip durch tuple, frozenset und unveränderbare String-Operationen unterstützt.


This site uses Just the Docs, a documentation theme for Jekyll.