Lokale Variable in Funktion wird automatisch zu globaler Variable

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hallo

Auf einer Webseite habe ich Python 2-Code gesehen, wo die Änderung des Wertes einer vermeintlich lokalen Variable den Wert einer globalen Variable ändert.

Code:

Code: Alles auswählen

# a global array
aa = [0, 1, 2]
print("Global:", id(aa))


def f():
    aa[0] = 88   # this is ok. global array will be updated
    print("Funktion f():", id(aa))


def g():
    aa = []     # WRONG! global array will NOT be updated
    print("Funktion g():", id(aa))


f()
print(aa)                        # prints [88, 1, 2]

g()
print(aa)                        # prints [88, 1, 2]
Warum ist die Variable `aa` in der Funktion `f()` eine globale Variable?

Gruß
Atalanttore
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Weil ›aa‹ in ›f‹ nicht definiert wird, also irgendwo außerhalb, ergo global, definiert sein muß.
Nur die Kommentare sind durcheinander, im ersten Fall sollte FETT ”wrong“ stehen, weil man nicht wild Listen verändern sollte, ›g‹ ist ok, da passiert nicht schlimmes.
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Warum sollte `aa` in `f()` keine globale Variable sein?

Die Entscheidung ob ein Name lokal ist oder nicht trifft der Compiler wenn er über eine Zuweisung an den Namen findet. In `f()` gibt es keine Zuweisung an den Namen → `aa` ist nicht lokal. In `g()` gibt es eine Zuweisung an den Namen → `aa` ist lokal.

Wenn Du das bisher nicht gewusst hast, dann frage ich mich wie Du so lange ”unfallfrei” mit Python klar gekommen bist. Das ist ja nicht gerade unwichtig. :-)
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@Sirius3 & __blackjack__: Also ist die Änderung des Wertes eines Elements in einer Liste über den Index keine Zuweisung?

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Doch das ist eine Zuweisung. Aber keine Zuweisung an den *Namen*. Um den geht es ja.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Murmeltiere. Überall Murmeltiere.

@Attalantore: Pythons Objekte können veränderlich oder nicht sein. Eine Liste ist es. Und da du an die Liste auf Moduleben rankommst, kannst du sie auch verändern.

Was du NICHT kannst (ohne global) ist dem Namen aa ein neues Objekt zuweisen. Und das ist der Unterschied. Jetzt gibt’s natürlich so ein paar Schlaumeier (Alfons M, anybody?) die sagen “wo nicht global dran steht, ist nicht global drin”.

Und das ist natürlich Unfug. Dieses Vorgehen mit aa ist keine deut besser. Nicht das Schlüsselwort global ist böse. Sondern das Konzept, in einer Funktion Zustand zu ändern, der dauerhaft geändert bleibt.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

__deets__ hat geschrieben: Sonntag 9. Juni 2019, 21:47 Was du NICHT kannst (ohne global) ist dem Namen aa ein neues Objekt zuweisen. Und das ist der Unterschied. Jetzt gibt’s natürlich so ein paar Schlaumeier (Alfons M, anybody?) die sagen “wo nicht global dran steht, ist nicht global drin”.
Meinst du mit "Objekt zuweisen" dem bestehenden Zeiger auf einen Speicherbereich einen anderen neuen Speicherbereich zuzuweisen?

Gruß
Atalanttore
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Mit "Objekt zuweisen" meint __deets__ schlicht

Code: Alles auswählen

aa = neues Objekt
Denn damit weist man einem Namen ein Objekt zu.
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Atalanttore: Zuweisungen gelten grundsätzlich nur für den lokalen Namensraum. Innere Namensräume (d.h. diejenigen "unterhalb" dieses Namensraums) können entscheiden ob sie eine eigene Zuweisung machen oder ob sie eine "höher gelegene" Zuweisung verwenden. Zur Veranschaulichung hier dargestellt mit inneren Funktionen:

Code: Alles auswählen

def f():
    x = 1
    def g():
        x = 2
        print(f'Inside g(): x is {x}')
        return x
    print(f'Return value of g(): {g()}')
    print(f'Original x inside f(): {x}')
    return x

def f2():
    x = 1
    def g():
        print(f'g() uses outer x: {x}')
        return x
    print(f'Return value of g(): {g()}')
    print('Adding return value to x...')
    x += g()
    print(f'Outer x is now {x}')
    print('Calling g() again...')
    print(f'Return value of g(): {g()}')
    return x
Bei deinem eingangs gezeigten Code-Beispiel wird ähnlich wie hier in f2() einfach das aa aus dem äußeren Namensraum angesprochen. Sobald man es einmal hat, unterscheiden sich die Zugriffsmöglichkeiten nicht vom "eigenen" Namensraum des Objekts. Eine Liste kann also im inneren Namensraum auf die gleiche Weise verändert werden wie in einem äußeren Namensraum. Die Regeln ob etwas lokal ist, gelten nur für den Zugriff auf den eigentlichen Bezeichner, nicht aber für das Verhalten des Objektes. Denn dieses weiß grundsätzlich nicht, in welchem Namensraum es "geholt" wurde (obskure Tricks mit dem Aufruf-Stack mal ausgenommen). Ist es so etwas klarer für dich...?
Benutzeravatar
snafu
User
Beiträge: 6866
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Atalanttore hat geschrieben: Montag 10. Juni 2019, 18:32
__deets__ hat geschrieben: Sonntag 9. Juni 2019, 21:47 Was du NICHT kannst (ohne global) ist dem Namen aa ein neues Objekt zuweisen. Und das ist der Unterschied. Jetzt gibt’s natürlich so ein paar Schlaumeier (Alfons M, anybody?) die sagen “wo nicht global dran steht, ist nicht global drin”.
Meinst du mit "Objekt zuweisen" dem bestehenden Zeiger auf einen Speicherbereich einen anderen neuen Speicherbereich zuzuweisen?
Das hast du jetzt wahrscheinlich irgendwo ergoogelt. Das Konzept von Zeigern und Speicherbereichen kennt Python nicht. Solche Erklärungen taugen eher für Sprachen wie C oder C++. Python kennt nur Objekte und Namen. Was die konkrete Python-Implementierung intern macht, sollte hierbei keine Rolle spielen.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@snafu: Danke für den Code und die Erklärung. Es ist jetzt "etwas" klarer.

Gruß
Atalanttore
Antworten