Kapitel 07 • Fortgeschrittenes OOP

Referenzen, Speicher & Stammbรคume ๐Ÿง ๐ŸŒณ

Verstehe, wie Python Objekte im Arbeitsspeicher verwaltet, was Aliasing bedeutet und baue einen echten Familienstammbaum.

๐Ÿ“‚ Dateien dieser Einheit:
๐Ÿ“„ aufgabe.py (Startercode) ๐Ÿงช test_aufgabe.py (Tests) ๐Ÿ’ก musterloesung.py (Lรถsung) ๐Ÿ“– README.md

1. Was ist eine Referenz? (Variablen sind Namensschilder)

Viele glauben, eine Variable sei eine Box, in der das Objekt direkt drinliegt. In Python ist das anders: Eine Variable ist in Wirklichkeit ein Zeiger (eine Referenz) auf einen Bereich im Arbeitsspeicher (RAM).

๐Ÿท๏ธ Die Namensschild-Analogie:
Stelle dir ein Haus vor. Das Haus steht an einer festen Adresse. Die Variable ist nur ein Adresszettel. Wenn du schreibst b = a, baust du kein zweites Haus, sondern schreibst die gleiche Adresse einfach auf einen zweiten Zettel!

Das Phรคnomen: Was passiert bei b = a?

Beispiel: Listen-Referenzen (Aliasing)
liste_a = [1, 2, 3]
liste_b = liste_a     # liste_b zeigt auf GENAU DIESELBE Liste im Speicher!

liste_b.append(99)

print(liste_a)  # Ausgabe: [1, 2, 3, 99] <-- liste_a hat sich mitverรคndert!
๐Ÿง  Was passiert im Computer-Speicher? (Notional Machine)
STACK (Variablen-Namen)                HEAP (Echter Speicher / RAM)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  liste_a โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚  ID: 0x7ffd1a  [1, 2, 3, 99] โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                                       โ–ฒ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                       โ”‚
โ”‚  liste_b โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
(Beide Variablen zeigen auf denselben Pfeil im Heap!)
        
โš ๏ธ Vorsicht bei verรคnderlichen Objekten (Mutable vs. Immutable):
  • Mutable (verรคnderlich): Listen, Dictionaries, eigene Klassenobjekte. Wenn du sie an einer Stelle รคnderst, รคndern sich alle Variablen, die darauf zeigen!
  • Immutable (unverรคnderlich): Zahlen (int, float), Texte (str), Tupel (tuple). Beim ร„ndern wird automatisch ein neues Objekt im Speicher erzeugt.

2. Der Unterschied zwischen == und is

In Python gibt es zwei Arten von Vergleichen:

Operator Bedeutung Frage im Hintergrund
== Wertegleichheit Haben beide Objekte denselben Inhalt?
is Identitรคt Sind beide Variablen exakt dasselbe Objekt an derselben Speicheradresse?
x = [1, 2, 3]
y = [1, 2, 3]
z = x

print(x == y)  # True  (weil der Inhalt gleich ist)
print(x is y)  # False (zwei getrennte Listen im Speicher)
print(x is z)  # True  (z zeigt direkt auf dieselbe Liste wie x)

3. Praxisbeispiel: Der Familienstammbaum ๐ŸŒณ

Warum sind Referenzen so genial? Weil ein und dasselbe Objekt in vielen Beziehungen vorkommen kann. Eine Person namens Susi ist gleichzeitig die Mutter von Erika, das Kind von Fritz und die Schwester von Tom.

Stammbaum mit Klassen-Referenzen
class Person:
    def __init__(self, name: str, geburtsjahr: int):
        self.name: str = name
        self.geburtsjahr: int = geburtsjahr
        self.mutter: Person | None = None   # Referenz auf Mutter-Objekt
        self.vater: Person | None = None    # Referenz auf Vater-Objekt
        self.kinder: list[Person] = []      # Liste von Referenzen auf Kinder

    def mutter_setzen(self, mutter: 'Person') -> None:
        self.mutter = mutter
        if self not in mutter.kinder:
            mutter.kinder.append(self)

    def __str__(self) -> str:
        return f"{self.name} (*{self.geburtsjahr})"

4. ๐ŸŽฏ Deine Aufgaben in aufgabe.py

ร–ffne die Datei aufgabe.py und vervollstรคndige die Stammbaum-Klasse:

๐Ÿ’ก Lรถsungshinweise (Aufklappen bei Bedarf)

๐Ÿ” Tipp zu TODO 4 (Geschwister finden)

Gehe alle Kinder der Mutter und alle Kinder des Vaters durch. Achte darauf, dass du kind is not self prรผfst, damit man nicht selbst als Geschwisterteil gelistet wird, und fรผge niemanden doppelt hinzu!

๐Ÿ” Tipp zu TODO 5 (GroรŸeltern finden)
ge = []
if self.mutter:
    if self.mutter.mutter: ge.append(self.mutter.mutter)
    if self.mutter.vater: ge.append(self.mutter.vater)
if self.vater:
    if self.vater.mutter: ge.append(self.vater.mutter)
    if self.vater.vater: ge.append(self.vater.vater)
return ge

5. ๐Ÿงช Lรถsung รผberprรผfen

Fรผhre im Terminal im Ordner 07_referenzen_und_speicher folgenden Befehl aus:

Terminal
python3 test_aufgabe.py