Warum kann eine Funktion einige Argumente ändern, wie sie vom Aufrufer wahrgenommen werden, andere jedoch nicht?

Lesezeit: 7 Minuten

Benutzer-Avatar
FMc

Ich versuche, Pythons Ansatz zum Variablenbereich zu verstehen. Warum ist in diesem Beispiel f() in der Lage, den Wert von zu ändern xwie innen wahrgenommen main()aber nicht der Wert von n?

def f(n, x):
    n = 2
    x.append(4)
    print('In f():', n, x)

def main():
    n = 1
    x = [0,1,2,3]
    print('Before:', n, x)
    f(n, x)
    print('After: ', n, x)

main()

Ausgabe:

Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After:  1 [0, 1, 2, 3, 4]

Benutzer-Avatar
jfs

Einige Antworten enthalten das Wort “Kopieren” im Kontext eines Funktionsaufrufs. Ich finde es verwirrend.

Python kopiert nicht Objekte Sie übergeben während eines Funktionsaufrufs je.

Funktionsparameter sind Namen. Wenn Sie eine Funktion aufrufen, bindet Python diese Parameter an beliebige Objekte, die Sie übergeben (über Namen in einem Aufrufbereich).

Objekte können veränderlich (wie Listen) oder unveränderlich (wie Ganzzahlen, Strings in Python) sein. Veränderliches Objekt, das Sie ändern können. Sie können einen Namen nicht ändern, Sie können ihn nur an ein anderes Objekt binden.

Ihr Beispiel ist nicht etwa Geltungsbereiche oder Namespaceses geht um Benennung und Bindung und Veränderlichkeit eines Objekts in Python.

def f(n, x): # these `n`, `x` have nothing to do with `n` and `x` from main()
    n = 2    # put `n` label on `2` balloon
    x.append(4) # call `append` method of whatever object `x` is referring to.
    print('In f():', n, x)
    x = []   # put `x` label on `[]` ballon
    # x = [] has no effect on the original list that is passed into the function

Hier sind schöne Bilder auf den Unterschied zwischen Variablen in anderen Sprachen und Namen in Python.

  • Dieser Artikel hat mir geholfen, das Problem besser zu verstehen, und er schlägt eine Problemumgehung und einige fortgeschrittene Anwendungen vor: Standardparameterwerte in Python

    – Gfi

    5. Juni 2011 um 16:48 Uhr

  • @Gfy, ich habe schon ähnliche Beispiele gesehen, aber für mich beschreibt es keine reale Situation. Wenn Sie etwas ändern, das übergeben wurde, macht es keinen Sinn, ihm einen Standardwert zu geben.

    – Markieren Sie Lösegeld

    15. August 2012 um 18:16 Uhr

  • @MarkRansom, ich denke, es ist sinnvoll, wenn Sie ein optionales Ausgabeziel wie folgt angeben möchten: def foo(x, l=None): l=l or []; l.append(x**2); return l[-1].

    – Janusz Lenar

    31. August 2012 um 13:03 Uhr

  • Für die letzte Zeile von Sebastians Code hieß es: “# the above has no effect on the original list “. Aber meiner Meinung nach hat es nur keine Auswirkung auf “n”, sondern hat das “x” in der Funktion main() geändert. Hab ich recht?

    – Benutzer17670

    26. September 2015 um 20:55 Uhr

  • @user17670: x = [] in f() hat keine Auswirkung auf die Liste x in der Hauptfunktion. Ich habe den Kommentar aktualisiert, um ihn genauer zu machen.

    – jfs

    27. September 2015 um 2:33 Uhr


Benutzer-Avatar
John Fouhy

Sie haben bereits eine Reihe von Antworten erhalten, und ich stimme JF Sebastian weitgehend zu, aber Sie könnten dies als Abkürzung nützlich finden:

Jedes Mal, wenn Sie sehen varname =erstellen Sie eine Neu Namensbindung innerhalb des Geltungsbereichs der Funktion. Welchen Wert auch immer varname vorher gebunden war, ist verloren innerhalb dieses Rahmens.

Jedes Mal, wenn Sie sehen varname.foo() Sie rufen eine Methode auf varname. Die Methode kann varname ändern (zB list.append). varname (oder vielmehr das Objekt that varname Namen) kann in mehr als einem Bereich vorhanden sein, und da es sich um dasselbe Objekt handelt, sind alle Änderungen in allen Bereichen sichtbar.

[note that the global keyword creates an exception to the first case]

Benutzer-Avatar
Konrad Rudolf

f ändert nicht wirklich den Wert von x (was immer derselbe Verweis auf eine Instanz einer Liste ist). Vielmehr verändert es die Inhalt dieser Liste.

In beiden Fällen a Kopie einer Referenz wird an die Funktion übergeben. Innerhalb der Funktion

  • n bekommt einen neuen Wert zugewiesen. Nur die Referenz innerhalb der Funktion wird geändert, nicht die außerhalb.
  • x wird kein neuer Wert zugewiesen: Weder die Referenz innerhalb noch außerhalb der Funktion wird geändert. Stattdessen, x‘s Wert wird modifiziert.

Da sowohl die x innerhalb und außerhalb der Funktion beziehen sich auf denselben Wert, beide sehen die Modifikation. Im Gegensatz dazu die n innerhalb der Funktion und außerhalb beziehen sich auf anders Werte nach n wurde innerhalb der Funktion neu zugewiesen.

  • “kopieren” ist irreführend. Python hat keine Variablen wie C. Alle Namen in Python sind Referenzen. Sie können den Namen nicht ändern, Sie können ihn nur an ein anderes Objekt binden, das ist alles. Es macht nur Sinn, von veränderlich und unveränderlich zu sprechen Objekt in Python sind sie keine Namen.

    – jfs

    22. Februar 2009 um 17:16 Uhr

  • @JF Sebastian: Deine Aussage ist bestenfalls irreführend. Es ist nicht sinnvoll, sich Zahlen als Referenzen vorzustellen.

    – Pitarou

    22. Februar 2009 um 17:33 Uhr

  • @dysfunctor: Zahlen sind Verweise auf unveränderliche Objekte. Wenn Sie sie lieber anders sehen möchten, müssen Sie einige seltsame Sonderfälle erklären. Wenn Sie sie als unveränderlich betrachten, gibt es keine Sonderfälle.

    – S. Lott

    22. Februar 2009 um 17:37 Uhr

  • @S.Lott: Unabhängig davon, was unter der Haube vor sich geht, Guido van Rossum hat sich viel Mühe gegeben, Python so zu entwerfen, dass der Programmierer Zahlen als nur … Zahlen betrachten kann.

    – Pitarou

    22. Februar 2009 um 18:00 Uhr

  • @JF, die Referenz wird kopiert.

    – Habnabit

    22. Februar 2009 um 18:02 Uhr

Ich werde Variablen umbenennen, um Verwirrung zu vermeiden. n -> nf oder nmain. x -> xf oder xmain:

def f(nf, xf):
    nf = 2
    xf.append(4)
    print 'In f():', nf, xf

def main():
    nmain = 1
    xmain = [0,1,2,3]
    print 'Before:', nmain, xmain
    f(nmain, xmain)
    print 'After: ', nmain, xmain

main()

Wenn Sie die Funktion aufrufen ferstellt die Python-Laufzeit eine Kopie davon xmain und ordnet es zu xfund weist auf ähnliche Weise eine Kopie von zu nmain zu nf.

Im Falle des nist der kopierte Wert 1.

Im Falle des x Der kopierte Wert ist nicht die wörtliche Liste [0, 1, 2, 3]. Es ist ein Hinweis zu dieser Liste. xf und xmain zeigen auf die gleiche Liste, also beim Ändern xf du änderst auch xmain.

Wenn Sie jedoch so etwas schreiben würden:

    xf = ["foo", "bar"]
    xf.append(4)

das würdest du finden xmain hat sich nicht geändert. Dies liegt daran, in der Zeile xf = [“foo”, “bar”] du hast Wechselgeld xf auf a zeigen Neu aufführen. Alle Änderungen, die Sie an dieser neuen Liste vornehmen, haben keine Auswirkungen auf die Liste xmain weist noch darauf hin.

Ich hoffe, das hilft. 🙂

Wenn die Funktionen mit völlig anderen Variablen neu geschrieben werden und wir aufrufen Ich würde auf ihnen veranschaulicht es dann den Punkt gut. Ich habe das zuerst nicht verstanden und den Beitrag von jfs mit dem gelesen tolle erklärungalso habe ich versucht, mich zu verstehen / zu überzeugen:

def f(y, z):
    y = 2
    z.append(4)
    print ('In f():             ', id(y), id(z))

def main():
    n = 1
    x = [0,1,2,3]
    print ('Before in main:', n, x,id(n),id(x))
    f(n, x)
    print ('After in main:', n, x,id(n),id(x))

main()
Before in main: 1 [0, 1, 2, 3]   94635800628352 139808499830024
In f():                          94635800628384 139808499830024
After in main: 1 [0, 1, 2, 3, 4] 94635800628352 139808499830024

z und x haben dieselbe ID. Nur unterschiedliche Tags für dieselbe zugrunde liegende Struktur, wie der Artikel sagt.

  • Komischerweise funktioniert dieser Link bei mir nicht

    – jtlz2

    6. Mai um 11:36 Uhr

  • Ja – ich schätze, nach ein paar Jahren könnte das passieren …

    – Jouell

    6. Mai um 21:42 Uhr


Benutzer-Avatar
Luis Damim

Das liegt daran, dass eine Liste ein veränderliches Objekt ist. Sie setzen x nicht auf den Wert von [0,1,2,3]definieren Sie ein Label für das Objekt [0,1,2,3].

Sie sollten Ihre Funktion f() wie folgt deklarieren:

def f(n, x=None):
    if x is None:
        x = []
    ...

  • Komischerweise funktioniert dieser Link bei mir nicht

    – jtlz2

    6. Mai um 11:36 Uhr

  • Ja – ich schätze, nach ein paar Jahren könnte das passieren …

    – Jouell

    6. Mai um 21:42 Uhr


Benutzer-Avatar
abukaj

Mein allgemeines Verständnis ist, dass jede Objektvariable (wie unter anderem eine Liste oder ein Diktat) durch ihre Funktionen geändert werden kann. Was ich glaube, dass Sie nicht in der Lage sind, den Parameter neu zuzuweisen – dh ihn als Referenz innerhalb einer aufrufbaren Funktion zuzuweisen.

Das stimmt mit vielen anderen Sprachen überein.

Führen Sie das folgende kurze Skript aus, um zu sehen, wie es funktioniert:

def func1(x, l1):
    x = 5
    l1.append("nonsense")

y = 10
list1 = ["meaning"]
func1(y, list1)
print(y)
print(list1)

  • Es gibt keine “Objektvariablen”. Alles ist ein Objekt in Python. Einige Objekte legen Mutator-Methoden offen (dh sie sind änderbar), andere nicht.

    – juanpa.arrivillaga

    11. August 2020 um 10:20 Uhr

  • Bro die Ausgabe am Ende fehlt. Was ist das Ergebnis?

    – Kettentreppe

    16. April 2021 um 12:26 Uhr

1054810cookie-checkWarum kann eine Funktion einige Argumente ändern, wie sie vom Aufrufer wahrgenommen werden, andere jedoch nicht?

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

Privacy policy