Python-Pandas-Datenrahmen, ist es Pass-by-Value oder Pass-by-Referenz?

Lesezeit: 6 Minuten

Python Pandas Datenrahmen ist es Pass by Value oder Pass by Referenz
nein

Wenn ich einen Datenrahmen an eine Funktion übergebe und ihn innerhalb der Funktion ändere, ist es dann eine Wertübergabe oder eine Referenzübergabe?

Ich führe folgenden Code aus

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
def letgo(df):
    df = df.drop('b',axis=1)
letgo(a)

der Wert von a ändert sich nach dem Funktionsaufruf nicht. Bedeutet das, dass es sich um einen Wertübergabe handelt?

Folgendes habe ich auch probiert

xx = np.array([[1,2], [3,4]])
def letgo2(x):
    x[1,1] = 100
def letgo3(x):
    x = np.array([[3,3],[3,3]])

Es stellt sich heraus letgo2() ändert sich xx und letgo3() nicht. Warum ist das so?

Python Pandas Datenrahmen ist es Pass by Value oder Pass by Referenz
Matthias Fripp

Die kurze Antwort lautet, Python führt immer eine Wertübergabe durch, aber jede Python-Variable ist tatsächlich ein Zeiger auf ein Objekt, sodass sie manchmal wie eine Referenzübergabe aussieht.

In Python ist jedes Objekt entweder veränderbar oder nicht veränderbar. zB sind Listen, Diktate, Module und Pandas-Datenrahmen änderbar, und Ints, Strings und Tupel sind nicht änderbar. Veränderbare Objekte können intern geändert werden (zB ein Element zu einer Liste hinzufügen), nicht veränderliche Objekte jedoch nicht.

Wie ich eingangs sagte, können Sie sich jede Python-Variable als Zeiger auf ein Objekt vorstellen. Wenn Sie einer Funktion eine Variable übergeben, ist die Variable (Zeiger) innerhalb der Funktion immer eine Kopie der übergebenen Variablen (Zeiger). Wenn Sie also der internen Variablen etwas Neues zuweisen, ändern Sie nur die lokale Variable, um auf ein anderes Objekt zu verweisen. Dies ändert (mutiert) weder das ursprüngliche Objekt, auf das die Variable zeigte, noch zeigt es die externe Variable auf das neue Objekt. An diesem Punkt zeigt die externe Variable noch auf das ursprüngliche Objekt, aber die interne Variable zeigt auf ein neues Objekt.

Wenn Sie das Originalobjekt ändern möchten (nur bei veränderbaren Datentypen möglich), müssen Sie etwas tun, das das Objekt ändert ohne der lokalen Variablen einen komplett neuen Wert zuweisen. Deshalb letgo() und letgo3() Lassen Sie das externe Element unverändert, aber letgo2() ändert es.

Wie @ursan betonte, wenn letgo() stattdessen so etwas verwendet, dann würde es das ursprüngliche Objekt ändern (mutieren), das df zeigt auf, was den über das globale angezeigten Wert ändern würde a Variable:

def letgo(df):
    df.drop('b', axis=1, inplace=True)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a)  # will alter a

In einigen Fällen können Sie die ursprüngliche Variable vollständig aushöhlen und mit neuen Daten füllen, ohne eine direkte Zuweisung vorzunehmen, z. B. ändert dies das ursprüngliche Objekt, das v weist darauf hin, wodurch sich die angezeigten Daten ändern, wenn Sie verwenden v später:

def letgo3(x):
    x[:] = np.array([[3,3],[3,3]])

v = np.empty((2, 2))
letgo3(v)   # will alter v

Beachten Sie, dass ich nichts direkt zuweise zu x; Ich ordne etwas dem gesamten internen Bereich von . zu x.

Wenn Sie unbedingt ein komplett neues Objekt erstellen und nach außen sichtbar machen müssen (was bei Pandas manchmal der Fall ist), haben Sie zwei Möglichkeiten. Die ‘saubere’ Option wäre nur das neue Objekt zurückzugeben, z.

def letgo(df):
    df = df.drop('b',axis=1)
    return df

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
a = letgo(a)

Eine andere Möglichkeit wäre, außerhalb Ihrer Funktion zu greifen und direkt eine globale Variable zu ändern. Das ändert sich a um auf ein neues Objekt zu zeigen, und jede Funktion, die auf . verweist a Danach wird das neue Objekt angezeigt:

def letgo():
    global a
    a = a.drop('b',axis=1)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo()   # will alter a!

Das direkte Ändern globaler Variablen ist normalerweise eine schlechte Idee, denn jeder, der Ihren Code liest, wird es schwer haben herauszufinden, wie das geht a wurde geändert. (Ich verwende im Allgemeinen globale Variablen für gemeinsame Parameter, die von vielen Funktionen in einem Skript verwendet werden, aber ich lasse sie diese globalen Variablen nicht ändern.)

Um @ Mike Grahams Antwort hinzuzufügen, der auf eine sehr gute Lektüre hinwies:

Was in Ihrem Fall wichtig ist, ist der Unterschied zwischen Namen und Werte. a, df, xx, x, sind alle Namen, aber sie beziehen sich auf dasselbe oder unterschiedliche Werte an verschiedenen Stellen deiner Beispiele:

  • Im ersten Beispiel, letgo bindet df auf einen anderen Wert, weil df.drop gibt ein neues zurück DataFrame es sei denn, Sie legen das Argument fest inplace = True (siehe Dokument). Das bedeutet, dass der Name df (lokal zu den letgo Funktion), die sich auf den Wert von bezog a, bezieht sich jetzt auf einen neuen Wert, hier der df.drop Rückgabewert. Der Wert a bezieht sich auf existiert noch und hat sich nicht geändert.

  • Im zweiten Beispiel, letgo2 mutiert x, ohne es neu zu binden, weshalb xx wird modifiziert von letgo2. Im Gegensatz zum vorherigen Beispiel ist hier der lokale Name x bezieht sich immer auf den Wert des Namens xx bezieht sich auf und ändert diesen Wert an Ort und Stelle, weshalb der Wert xx sich bezieht, hat sich geändert.

  • Im dritten Beispiel, letgo3 bindet x zu einem neuen np.array. Das verursacht den Namen x, lokal zu letgo3 und zuvor auf den Wert von bezogen xx, um jetzt auf einen anderen Wert zu verweisen, den neuen np.array. Der Wert xx sich bezieht, hat sich nicht geändert.

Die Frage ist nicht PBV vs. PBR. Diese Namen verursachen nur in einer Sprache wie Python Verwirrung; sie wurden für Sprachen erfunden, die wie C oder Fortran funktionieren (als Quintessenz der PBV- und PBR-Sprachen). Es ist wahr, aber nicht aufschlussreich, dass Python immer einen Wert übergibt. Hier stellt sich die Frage, ob der Wert selbst mutiert ist oder ob Sie einen neuen Wert erhalten. Pandas irren normalerweise auf der Seite der letzteren.

http://nedbatchelder.com/text/names.html erklärt sehr gut, was Pythons Namenssystem ist.

  • Die Semantik des Übergebens und Zuweisens in Python ist genau die gleiche wie in Java, und die gleichen Dinge, die Sie sagen, können auch auf Java angewendet werden. Auf StackOverflow und anderswo im Internet finden es die Leute jedoch anscheinend “aufschlussreich”, Ihnen zu vermitteln, dass Java immer als Wertüberschreitung gilt, wenn dieses Problem auftaucht.

    – neuacct

    12. August ’16 um 2:35

Hier ist das Dokument zum Ablegen:

Geben Sie ein neues Objekt mit entfernten Beschriftungen in der angeforderten Achse zurück.

So wird ein neuer Datenrahmen erstellt. Das Original hat sich nicht verändert.

Aber wie bei allen Objekten in Python wird der Datenrahmen per Referenz an die Funktion übergeben.

  • Ich muss Stack Exchange lieben

    – Dan

    14. März ’21 um 20:31

Sie müssen ‘a’ am Anfang der Funktion global machen, sonst ist es eine lokale Variable und ändert das ‘a’ im Hauptcode nicht.

.

183480cookie-checkPython-Pandas-Datenrahmen, ist es Pass-by-Value oder Pass-by-Referenz?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy