Python-Referenzübergabe: Anwendungsfälle für veränderbare vs. unveränderbare Objekte

1. Unterschied zwischen Übergabe per Wert und Übergabe per Referenz

In Python gibt es zwei Möglichkeiten, Argumente an Funktionen zu übergeben: Übergabe per Wert und Übergabe per Referenz.

  • Pass-by-Value: Eine Methode, bei der eine Kopie des Wertes als Argument an die Funktion übergeben wird; das Ändern des Parameters innerhalb der Funktion wirkt sich nicht auf die ursprüngliche Variable aus.
  • Pass-by-Reference: Eine Methode, bei der eine Referenz (Adresse) auf die Variable an die Funktion übergeben wird, sodass Änderungen innerhalb der Funktion im Originalobjekt sichtbar werden.

In Python variiert dieses Verhalten je nach Art des Objekts. Das „Pass-by-Reference“-Verhalten von Python gilt insbesondere für veränderbare (mutable) Datentypen und kann das Verhalten von Code erheblich beeinflussen, daher ist es wichtig, es korrekt zu verstehen.

2. Merkmale von Objekten in Python

In Python werden alle Daten als Objekte behandelt und anhand ihrer Objektmerkmale entweder als unveränderlich (immutable, können nicht geändert werden) oder veränderlich (mutable, können geändert werden) klassifiziert. Diese Unterscheidung beeinflusst ihr Verhalten, wenn sie als Argumente an Funktionen übergeben werden.

  • Unveränderliche Objekte: Objekte, die nach ihrer Erstellung nicht mehr modifiziert werden können. Beispiele sind Ganzzahlen ( int ), Fließkommazahlen ( float ), Zeichenketten ( str ), Tupel ( tuple ). Da diese Datentypen nach ihrer Erstellung nicht geändert werden können, wirken sich Operationen auf sie innerhalb einer Funktion nicht auf den Aufrufer aus, selbst wenn sie per Referenz übergeben werden.
  • Veränderliche Objekte: Objekte, die nach ihrer Erstellung modifiziert werden können. Beispiele sind Listen ( list ), Wörterbücher ( dict ), Mengen ( set ). Da Änderungen an diesen Datentypen innerhalb einer Funktion im Aufrufer sichtbar werden, sind sie besonders vom Referenz‑Übergabeverhalten von Python betroffen.

侍エンジニア塾

3. Wie Python Argumente übergibt

In Python werden beim Übergeben von Argumenten an eine Funktion Referenzen auf Objekte übergeben. Dieses Verhalten wird manchmal als „Pass-by-Object-Reference“ bezeichnet. Im Folgenden gehen wir konkrete Beispiele durch, die das Verhalten von Python je nach Unveränderlichkeit oder Veränderlichkeit von Objekten veranschaulichen.

3.1 Unveränderliche Objekte

Wenn Sie ein unveränderliches Objekt an eine Funktion übergeben, erzeugt das Zuweisen eines neuen Wertes innerhalb der Funktion ein neues Objekt und beeinflusst das ursprüngliche Objekt nicht.

Beispiel: Übergabe einer unveränderlichen Ganzzahl

def modify_number(num):
    num = num * 2
    print("Number inside the function:", num)

original_num = 5
modify_number(original_num)
print("Number outside the function:", original_num)

Ausgabe:

Number inside the function: 10
Number outside the function: 5

Erklärung

Innerhalb der Funktion modify_number wird die Variable num verdoppelt, aber das beeinflusst original_num außerhalb der Funktion nicht. Da Ganzzahlen unveränderlich sind, wird beim Zuweisen eines neuen Wertes ein neues Objekt erstellt, und original_num bleibt unverändert.

3.2 Veränderliche Objekte

Im Gegensatz dazu wird beim Übergeben eines veränderlichen Objekts an eine Funktion dessen Referenz auch innerhalb der Funktion verwendet. Dadurch werden Änderungen, die innerhalb der Funktion vorgenommen werden, ebenfalls im Originalobjekt sichtbar.

Beispiel: Übergabe einer veränderlichen Liste

def add_item(my_list):
    my_list.append("Added element")
    print("List inside the function:", my_list)

original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)

Ausgabe:

List inside the function: ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2', 'Added element']

Erklärung

Da Listen veränderlich sind, werden die innerhalb der Funktion add_item vorgenommenen Änderungen direkt in original_list außerhalb der Funktion sichtbar. Auf diese Weise werden veränderliche Objekte zwischen Innen- und Außenbereich der Funktion geteilt, sodass Änderungen innerhalb der Funktion auch den Aufrufer beeinflussen.

4. Vorsichtsmaßnahmen und Gegenstrategien bei der Übergabe per Referenz

Passieren mutable Objekte an Funktionen in Python kann zu unerwartetem Verhalten führen. Hier sind einige Gegenmaßnahmen, um solche Probleme zu vermeiden.

4.1 Kopien von Objekten verwenden

Wenn Sie ein Objekt innerhalb einer Funktion ändern möchten, können Sie verhindern, dass das Original beeinflusst wird, indem Sie es vor den Änderungen kopieren. In Python können Sie das copy‑Modul verwenden, um flache Kopien (copy.copy) oder tiefe Kopien (copy.deepcopy) zu erstellen.

Beispiel: Deep Copy verwenden, um Probleme mit mutablen Objekten zu vermeiden

import copy

def add_item(my_list):
    my_list_copy = copy.deepcopy(my_list)
    my_list_copy.append("Added element")
    print("List inside the function (copy):", my_list_copy)

original_list = ["Element 1", "Element 2"]
add_item(original_list)
print("List outside the function:", original_list)

Ausgabe:

List inside the function (copy): ['Element 1', 'Element 2', 'Added element']
List outside the function: ['Element 1', 'Element 2']

Erklärung
Durch die Verwendung von deepcopy wird innerhalb der Funktion ein neues Objekt erstellt, sodass die ursprüngliche Liste unverändert bleibt. Das ermöglicht unabhängige Änderungen innerhalb und außerhalb der Funktion.

4.2 None für Standardargumente verwenden

Vermeiden Sie, mutable Objekte als Standardargumente einer Funktion zu setzen; es wird empfohlen, None als Standardwert zu verwenden und innerhalb der Funktion ein neues Objekt zu erzeugen.

Beispiel: Sichere Methode, das Standardargument None zu setzen

def add_item(my_list=None):
    if my_list is None:
        my_list = []
    my_list.append("New element")
    print("List inside the function:", my_list)
    return my_list

# When no list is passed
result = add_item()
print("Returned list:", result)

# When a list is passed
existing_list = ["Element 1", "Element 2"]
result = add_item(existing_list)
print("Returned list:", result)
print("Original list:", existing_list)

Ausgabe:

List inside the function: ['New element']
Returned list: ['New element']
List inside the function: ['Element 1', 'Element 2', 'New element']
Returned list: ['Element 1', 'Element 2', 'New element']
Original list: ['Element 1', 'Element 2', 'New element']

Erklärung
Durch die Verwendung des Standardarguments None und das Erzeugen einer neuen Liste innerhalb der Funktion können Sie verhindern, dass externe Listen unerwartet geändert werden. Das Setzen von None als Standardargument macht klar, ob eine neue Liste erstellt oder die übergebene verwendet werden soll.

侍エンジニア塾

5. Praktisches Beispiel: Code zum Vertiefen des Verständnisses von Pass‑by‑Reference

Lassen Sie uns das bisher Gelernte anhand eines praktischen Beispiels noch einmal durchgehen.

Beispiel: Ändern von Schlüsseln und Werten eines Dictionaries

Dictionaries sind mutable Objekte, sodass Operationen, die innerhalb einer Funktion ausgeführt werden, das Dictionary außerhalb der Funktion beeinflussen. Das folgende Beispiel zeigt das Verhalten beim Ändern von Schlüsseln und Werten eines Dictionaries.

def modify_dict(my_dict):
    my_dict["new key"] = "new value"
    print("Dictionary inside the function:", my_dict)

original_dict = {"key1": "value1", "key2": "value2"}
modify_dict(original_dict)
print("Dictionary outside the function:", original_dict)

Ausgabe:

Dictionary inside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}
Dictionary outside the function: {'key1': 'value1', 'key2': 'value2', 'new key': 'new value'}

Erklärung
Da Dictionaries mutable sind, werden Änderungen, die innerhalb der Funktion vorgenommen werden, auch im original_dict außerhalb der Funktion sichtbar. Wie bei Listen können Dictionaries den Aufrufer beeinflussen, weil sie per Referenz übergeben werden.

6. Zusammenfassung

Pythons „Pass‑by‑Reference“ verhält sich je nach Eigenschaften eines Objekts unterschiedlich, daher ist das Verständnis dafür nötig, um die Zuverlässigkeit Ihres Codes zu verbessern. Insbesondere, um unerwartetes Verhalten beim Übergeben von Referenzen auf mutable Objekte zu vermeiden, empfiehlt es sich, Kopieren und das Standardargument None zu nutzen.

Zusammenfassungspunkte

  • Unterschied zwischen Pass-by-Value und Pass-by-Reference : In Python hängt es davon ab, ob Änderungen innerhalb einer Funktion die ursprüngliche Variable beeinflussen, von der Art des Objekts ab.
  • Unveränderlich vs. veränderlich : Unveränderliche Objekte in Python spiegeln Änderungen, die innerhalb einer Funktion vorgenommen werden, nicht wider, während veränderliche Objekte über Referenzübergabe zwischen innerhalb und außerhalb der Funktion geteilt werden.
  • Minderungsstrategien : Für veränderliche Objekte sind Methoden wie die Verwendung von deepcopy aus dem copy‑Modul oder das Setzen von Standardargumenten auf None wirksam, um unerwartetes Verhalten zu vermeiden.

Ich hoffe, dieser Artikel hat Ihr Verständnis für Referenzübergaben in Python vertieft. Nutzen Sie dieses Wissen, um effizienten, weniger fehleranfälligen Code zu schreiben.