Seite 1 von 1
Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Montag 10. Juni 2019, 23:04
von Miranda
Hallo,
wieder einmal eine Frage. Das hier funktioniert:
Code: Alles auswählen
def spam():
print(eggs)
eggs=1
while eggs<10:
eggs = eggs +1
spam()
Ich kann lesend auf die Variable eggs zugreifen obwohl sie nicht in der Funktion definiert ist. Klar.
Sobald ich aber mit der Variablen arbeiten will - rummst es.
Code: Alles auswählen
def spam():
print(eggs)
eggs = eggs +1 #Hier knallt es - lesen geht, nur schreiben nicht.
eggs=1
while eggs<10:
eggs = eggs +1
spam()
Warum kann ich die Variable in der Funktion lesen, aber erst mir ihr rechnen, wenn ich sie (beispielsweise) mit eggs = 1 innerhalb der Funktion initialisiert habe.
Ich finde das irgendwie schwer zu durchschauen, das ist doch nichts halbes und nichts ganzes?
Grüße, Miranda
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Montag 10. Juni 2019, 23:23
von __deets__
Das ist eine Festlegung die man in Python gemacht hat, weil es keine explizite Deklaration von Variablen gibt. Dabei wird in einer Funktion einfach geschaut, ob eine Zuweisung an einen Namen stattfinden.
<name> = <ausdruck>
Es ist dabei völlig unerheblich WAS in <ausdruck> steht.
Und wenn sowas gefunden wird, dann wird <name> Zur lokalen Variable in der Funktion gemacht.
Andere Sprachen machen das anders. ZB JavaScript, da musst du beim ersten Mal der Verwendung var davor schreiben. Aber Python macht’s halt so. Kann man doof finden. Aber nicht ändern.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 06:20
von ThomasL
Miranda hat geschrieben: Montag 10. Juni 2019, 23:04
Ich finde das irgendwie schwer zu durchschauen, das ist doch nichts halbes und nichts ganzes?
Hallo Miranda, das ist sogar ganz einfach zu durchschauen.
Einfach weil so wie in deinem Beispiel macht man es NICHT.
Man macht es so:
Code: Alles auswählen
def spam(eggs):
print(eggs)
eggs = eggs + 1
return eggs
eggs = 1
while eggs < 10:
eggs = eggs + 1
eggs = spam(eggs)
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 07:25
von sparrow
Miranda hat geschrieben: Montag 10. Juni 2019, 23:04Ich finde das irgendwie schwer zu durchschauen, das ist doch nichts halbes und nichts ganzes?
Manchmal ist es ganz gut, Dinge nicht nur anhand eines einzigen Beispiels zu betrachten.
Was ThomasL geschrieben hat, solltest du beherzigen. In 99,99% der Fälle ist das Benutzen von globalen Variablen falsch. Es gilt: Eine Funktion bekommt die Variablen, die sie braucht, als Parameter übergeben und liefert das Ergebnis mit return zurück. Genau wie von Thomas beschrieben.
Warum kann man dann überhaupt auf Variablen des äußeren Namensraums zugreifen? Weil es für manche Variablen, sogenannte Konstanten, sinnvoll ist. Konstanten, wie der Name schon sagt, sind konstant und ändern sich nach der einmaligen Zuweisung nicht mehr. In anderen Programmiersprachen muss man die auch entsprechend deklarieren und kann sie hinterher gar nicht mehr ändern. Das wird bei Python, wie so vieles, durch Konvention gelöst. Man weiß, dass man Konstanten nicht ändert und tut das auch nicht . Es sei denn, man weiß was man tut und braucht das unbedingt.
In Python gibt es die Konvention Konstanten IN_GROSSBUCHSTABEN zu schreibe, damit jeder weiß: Alles klar, fester Wert.
Ein Beispiel wären Konstanten in der Mathematik (etwa Pi) oder so etwas wie ein fester Pfad oder die Benennung von Werten für ein leichteres Arbeiten (RED = 16, BLUE = 12 falls irgendwo Integerwerte als Farben verwendet werden). Es macht also durchaus Sinn, die "äußere" Variable in der Funktion lesen zu können. Sie ändern zu wollen, zeugt von schlechtem bis falschem Programmierstil.
Miranda hat geschrieben: Montag 10. Juni 2019, 23:04Warum kann ich die Variable in der Funktion lesen, aber erst mir ihr rechnen, wenn ich sie (beispielsweise) mit eggs = 1 innerhalb der Funktion initialisiert habe.
Wenn du innerhalb der Funktion "eggs = 1" schreibst, ist das nicht mehr die selbe Variable wie in der "äußeren" Umwelt. Die Funktion hat ihren eigenen Namensraum - und das ist auch gut so.
Code: Alles auswählen
>>> def test():
i = 1
i = i + 1
print(f"i in in test: {i}")
>>> i = -5
>>> test()
i in in test: 2
>>> i
-5
>>>
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 07:32
von Miranda
Hallo,
__deets__ hat geschrieben: Montag 10. Juni 2019, 23:23
...
Dabei wird in einer Funktion einfach geschaut, ob eine Zuweisung an einen Namen stattfinden.
<name> = <ausdruck>
Es ist dabei völlig unerheblich WAS in <ausdruck> steht.
...
Genau das wundert mich eben: Es ist ja
eben nicht vollkommen unerheblich was in <ausdruck> steht.
Das hätte ich ja erwartet.
Die Variable 'eggs' selbst darf dort im Ausdruck ja nicht stehen - sonst kommt es zu einem Fehler.
Und das wundert mich. Ich darf die Variable lesen - bekomme auch den Wert geliefert, der in dem Hauptprogramm steht. Ich darf die Variable in der Funktion auch überschreiben - nur darf sie nicht Teil des Ausdrucks sein.
Ich versuche nur zu verstehen warum man das in Python so zulässt. Es ist für mich unlogisch den Wert
- lesen zu können,
- die Variable lokal überschreiben zu können.
Aber beides in
Kombination geht nicht.
Da blättert mein Nagellack beim Lesen ab...
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 07:43
von sparrow
Ist doch ganz einfach. Du sagst "i =" damit existert im lokalen Namensraum eine nicht initialisierte Variable mit dem Namen "i". Und wenn du dann hinter dem Gleichheitszeichen anfängst, "i" zu verwenden, dann ist es halt nicht initialisiert.
Ich verstehe dein Problem nicht. Ich kenne keinen Praxisfall, in dem das relevant wäre. Dur regst dich völlig umsonst auf und verschwendest Lebenszeit.
Nochmal: Variablen als Parameter in die Funktion. Alles andere ist kaka.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 07:44
von Sirius3
Es gibt kein "Überschreiben". Eine Variable ist entweder im lokalen Namensraum definiert, oder außerhalb. Sobald eine Zuweisung stattfindet, nimmt Python an, die Variable wäre lokal. Und dann macht `eggs = eggs + 5` keinen Sinn mehr, weil der Wert von `eggs` nicht definiert ist, also eggs + 5 nicht berechnet werden kann.
Wie schon die anderen geschrieben haben, kommt der Fall, dass eine Variable einen globalen Wert hat und dann lokal geändert werden soll, nicht vor.
Es wäre doch sehr verwirrend, wenn ein globale Variable und eine lokale den selben Namen haben könnten.
Daher die Konvention, Konstanten komplett groß zu schreiben, dann ist bei Deinem Beispiel alles ok, falls `eggs` tatsächlich konstant wäre:
Bei Variablem `eggs` hat ThomasL bereits die Lösung geschrieben:
Code: Alles auswählen
def spam(eggs):
print(eggs)
eggs = eggs + 1
return eggs
def main():
eggs = 1
while eggs < 10:
eggs = eggs + 1
eggs = spam(eggs)
if __name__ == '__main__':
main()
Dass Fälle, die nicht vorkommen dürfen, zu Fehlermeldungen führen, finde ich ganz ok. Stell Dir nur die Verwirrung vor, wenn so komische Dinge, wie Du sie versuchst, erlaubt wären und es nur zur Laufzeit zu entscheiden wäre, ob eine Variable nun an der Stelle lokal oder global ist.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 09:01
von __blackjack__
@Miranda: Deine Aussage „das ist doch nichts halbes und nichts ganzes“ stimmt halt nicht – ein Name ist entweder lokal in der Funktion, und zwar an *jeder* Stelle, oder er ist nicht lokal, an *jeder* Stelle in der Funktion. Wenn er mal lokal und mal nicht-lokal wäre – *das* wäre verwirrend und nichts halbes und nichts ganzes.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Dienstag 11. Juni 2019, 14:33
von kbr
@Miranda: Stell Dir einmal vor, das ginge
und vor anlegen und zuweisen an das lokale Label "eggs" würde ein nicht lokales Label "eggs" referenziert werden. Wie würde sich dann der folgende Code verhalten?
Ab dem zweiten Durchlauf der Schleife hätte die dritte Zeile nun ein anderes Verhalten. Das wäre übel. Es ist daher alles richtig so, wie es ist.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Mittwoch 12. Juni 2019, 22:55
von Miranda
__blackjack__ hat geschrieben: Dienstag 11. Juni 2019, 09:01
@Miranda: Deine Aussage „das ist doch nichts halbes und nichts ganzes“ stimmt halt nicht – ein Name ist entweder lokal in der Funktion, und zwar an *jeder* Stelle, oder er ist nicht lokal, an *jeder* Stelle in der Funktion. Wenn er mal lokal und mal nicht-lokal wäre – *das* wäre verwirrend und nichts halbes und nichts ganzes.
Hallo,
genau das war es was mir gefehlt hat: Ich hatte nicht gesehen, dass es eine exklusive Sache ist. Also ist es entweder eine globale Variable, die nur gelesen wird oder es wird mit der Zuweisung zu einer rein lokalen Variablen.
_DAS_ ist für mich dann doch eingängig.
Vielen lieben Dank!!!
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Sonntag 16. Juni 2019, 15:20
von DeaD_EyE
Wieso nicht so:
Code: Alles auswählen
def spam(eggs):
"""
Hier nichts ausgeben, nur rechnen und den Wert dann zurück liefern.
Das ist was Funktionen eigentlich machen sollten.
Lieferst du einen Wert zurück und gibst gleichzeitig etwas in der Konsole aus
ist keine pure Funktion mehr. In anderen Sprachen unterscheidet man Funktionen
von Prozeduren, bei Python gibt es das nicht. Dennoch kann man sich daran orientieren.
Prozeduren machen irgendwas mit der Welt in der sie leben. Sie verändern sie in dem sie z.B. Text irgendwo ausgeben.
Funktionen rechnen nur und beeinflussen nicht die Welt.
Wenn man text ausgeben möchte, kann man dafür eine extra Funktion erstellen.
Die andere Funktion soll nichts weiter machen, als rechnen. Das hat den Vorteil, dass
du diese Funktion auch in anderen Teilen deines Programm nutzen kannst, ohne das etwas
in der Konsole an Text ausgeben wird.
Ich rege mich jedes mal darüber auf, wenn man wieder irgendein Framework mein Terminal zumüllt.
Da hat man das Problem, dass man das nicht so einfach abschalten kann, es seiden man verändert den Code des Framworks.
"""
return eggs +1
eggs=1
while eggs<10:
eggs = spam(eggs)
print(eggs)
oder Pythonic:
Globale Variablen braucht man nur selten.
Es kommt z.B. bei dem MicroWebFramework Flask vor. Dort lebt app auf Modulebene.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Montag 17. Juni 2019, 11:50
von DasIch
DeaD_EyE hat geschrieben: Sonntag 16. Juni 2019, 15:20
Globale Variablen braucht man nur selten.
Es kommt z.B. bei dem MicroWebFramework Flask vor. Dort lebt app auf Modulebene.
Auch bei Flask braucht man es nicht. Man es kann über das
Application Factory Pattern umgehen. Es ist bei nicht-trivialen Anwendungen auch definitiv zu empfehlen.
Re: Zugriff auf globale Variable - aber nur lesend klappts?!
Verfasst: Freitag 21. Juni 2019, 16:32
von DeaD_EyE
Und trotzdem wird es in jedem Tutorial falsch gelehrt. Ist ja auch bequem, bis man irgendwann über seinen eigenen Code stolpert.
Mit app auf Modulebene hatte ich bisher keine Probleme, aber wie du schon bereits geschrieben hast, spielt das erst bei komplexen Anwendungen eine Rolle.
Das eigentliche Problem ist, dass sich schlechte Angewohnheiten nicht so einfach abgewöhnen lassen. Gerade für Anfänger ist das ein Problem, wenn sie
es falsch lernen.