Seite 4 von 6

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 16:30
von pillmuncher
@Alfons Mittelmeyer: Schau dir mal diesen Vortrag von Brandon Rhodes an: The Clean Architecture in Python

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 16:50
von Alfons Mittelmeyer
__deets__ hat geschrieben:Die Tatsache das man etwas nicht tun sollte impliziert nicht, dass man es nicht tun darf. Man sollte es nur unter Abwaegung der Alternativen tun.
Was man nicht tun sollte, ist, ein Dogma aus etwas zu machen, das für einen ganz bestimmten Zusammenhang gemeint war.

Und der Zusammenhang ist, dass viele Anfänger nicht OOP programmieren und statt Klassen und statt Aufräumen eine Unzahl vom Modulinternen Variablen haben auf die sie zugreifen. Klar, dass man das nicht haben soll, sondern sauber aufgeräumt und gekapselt und sinnvoll gegliedert implementieren sollte.
__deets__ hat geschrieben:Es ist allgemein eine schlechte Idee, mit einem scharfen Gegenstand die Bauchhoehle zu eroeffnen. Das bedeutet aber deshalb nicht, dass man Chirurgie verbietet. Man sollte aber zum befestigen einer Hose einen Guertel verwenden, statt sie mit Darmschlingen zu verknoten.
Wie kommst Du auf diese komische Metapher mit dem scharfen Gegenstand?
__deets__ hat geschrieben:Globaler Zustand ist allgemein der Anus Praeter der Programmierung. Man will das nicht, es ist haesslich und macht das Leben schwerer, aber man kann's halt nicht immer vermeiden.
Allles ist möglich, man kann es es wahrscheinlich immer vermeiden, auch wenn man dann manchmal statt etwas Einfachem eine häßliche fehleranfällige Programmierung zu machen hat.

Bei diesem Beispiel: http://code.activestate.com/recipes/413 ... ython-way/
ist in Zeile 26 ein globales Objekt definiert:

features = FeatureBroker()

Warum wird das in diesem Forum so gesehen, als ob das ein Verbrechen ist oder jedenfalls als etwas, was es auf Teufel komm raus zu vermeiden gilt?

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 17:21
von __deets__
Das wird nicht nur so in diesem Forum so gesehen, sondern von jedem, der gut programmieren kann.

Und wann kommt mal der Moment an dem du begreifst, das ein Gegenbeispiel fuer eine *Richtlinie* nicht die gleichen Konsequenzen hat wie fuer einen mathematischen Beweis?

Wenn du hier Code schreibst, der unnoetigerweise global verwendet oder globalen Zustand zur Funktion vorraussetzt, bleibt das schlechter Code, und das wird dir dann auch weiterhin so gesagt werden. Die Existenz von anderem schlechten Code, oder Code der aufgrund bestimmter Randbedingungen so geschrieben werden musste aendert daran nix.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 17:44
von pillmuncher
Es ist doch ganz einfach. Ein gutes Programm sieht typischerweise so aus:

Bild

Ein weniger gutes typischerweise so:

Bild

Ersteres zeigt das Innenleben eines VIntage Hiwatt Amps (ich hab zwei davon), zweiteres das eines Vintage Fender Amps. Globaler Zustand führt typischerweise zu Programm-Strukturen, die aussehen wie das zweite Bild, das Vermeiden von globalem Zustand zu solchen, die aussehen wie das erste.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 19:52
von Alfons Mittelmeyer
pillmuncher hat geschrieben:Es ist doch ganz einfach. Ein gutes Programm sieht typischerweise so aus
Genau das ist der Zweck, warum man manchmal dasselbe Objekt global verfügbar machen sollte, anstatt es überall durchzureichen.

Ein System, besteht aus diversen Subsystemen. Bei der Initialisierung mancher Subsysteme wird zuerst ein Objekt instanziert, das noch weiter durch diverse Daten konfiguriert wird. Um mit diesen Subsystemen zu arbeiten, braucht man dann diese konfigurierten Objekte.
Doch was tun, wenn es heißt, daß man keine globalen Objekte haben soll, sonder nur Funktionen und Klassen?

Ich habe jetzt die Lösung gefunden.

Code: Alles auswählen

# statt 
my_object = _MyClass()

# und dann globalen Zugriff auf my_object, laesst sich das auch mit einem Singleton loesen:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

# python3
class MyClass(metaclass=Singleton):

    def __init__(self):
        self.number = 0

# test ----
a = MyClass()
a.number = 123
b = MyClass()
print(b.number)

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 20:20
von Sirius3
@Alfons Mittelmeyer: Du findest immer wieder andere Varianten, globale Variablen zu definieren. Es sind und bleiben aber globale Variablen. Singletons werden in Python nicht gebraucht, weil man ja prinzipiell globale Variablen definieren kann - für die wenigen Fälle, wo das wirklich sinnvoll ist. Singletons wurden für Sprachen erfunden, wo es keine globalen Variablen gibt, sich die Leute aber dennoch nicht davon abbringen ließen, welche zu benutzen.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 20:36
von kbr
pillmuncher hat geschrieben:Ein weniger gutes typischerweise so
Sensationell :D
Und wenn schon Singletons, dann Borgs.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 20:42
von Alfons Mittelmeyer
Sirius3 hat geschrieben:Singletons werden in Python nicht gebraucht, weil man ja prinzipiell globale Variablen definieren kann - für die wenigen Fälle, wo das wirklich sinnvoll ist.
Ja, und wenn für die wenigen Fälle, wo man es braucht, es immer wieder heißt, globale Variablen soll man nicht nehmen, dann bleiben nur Singletons übrig.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 21:06
von Sirius3
@Alfons Mittelmeyer: hallo, jemand zu Hause? Singletons sind globale Variablen. Wenn man globale Variablen braucht sollte man globale Variablen benutzen. Wenn man sie nicht unbedingt braucht, dann nicht.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Donnerstag 27. April 2017, 21:32
von Alfons Mittelmeyer
Sirius3 hat geschrieben:@Alfons Mittelmeyer: hallo, jemand zu Hause? Singletons sind globale Variablen. Wenn man globale Variablen braucht sollte man globale Variablen benutzen. Wenn man sie nicht unbedingt braucht, dann nicht.
Ok, das wollte ich wissen.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 06:13
von jerch
@Alfons Mittelmeyer:
Oder so:

Code: Alles auswählen

class World(object):
    import a
    def funcXY(self):
        ...
    ...
    def main(self):
        ...

World.main()
Damit ist fast alles über `self` erreichbar (mit etwas fummeln bekommt man auch die imports da dran). :lol:

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 07:50
von wuf
Hallo pillmuncher

viewtopic.php?p=308156#p308156

Danke und Gratulation für deinen Superbeitrag der mich vom gähnen erlöst hat. Übrigens auch das zweite Bild ist noch recht gut überblickbar!

Gruss wuf :wink:

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 08:57
von Alfons Mittelmeyer
@jerch: ja nichtglobal zu importieren, geht natürlich auch

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 10:46
von Sirius3
@jerch und Alfons Mittelmeyer: nein, nicht-global importieren geht gar nicht. Importe sind immer global. und wie wir schon ein paar Beiträge vorher gehört haben, sollte sobald das Programm mit der eigentlichen Arbeit anfängt, alle globalen Definitionen abgeschlossen sein, dazu gehören auch Importe. Zudem werden die Abhängigkeiten klar, wenn alle Importe am Anfang der Datei gefunden werden.

Und jetzt kommt wieder jemand mit Lazy- bzw. dynamischem Laden. Sowas sollte man sich gut Überlegen, ob man das wirklich braucht. Das macht Programme deutlich schwieriger zu Testen und erhöht die Komplexität nicht unerheblich. Das ist im Normalfall also nicht nötig oder empfehlenswert.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 10:57
von Alfons Mittelmeyer
Sirius3 hat geschrieben:Und jetzt kommt wieder jemand mit Lazy- bzw. dynamischem Laden
Nein damit komme ich bestimmt nicht, beim dynamischen Laden statt import, würde ja die Variable neu kreiert und wäre damit eine neue Instanz.

Das wäre vergleichbar damit:

Code: Alles auswählen

def getvar():
    return [5]

def main():
    a = getvar()
    print(a)
    b = getvar()
    a[0] = 7
    b[0] = 6
    print(a,b)

main()

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 20:06
von jerch
Also ich fand die Idee gut, so konzeptionös...

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 21:53
von Alfons Mittelmeyer
jerch hat geschrieben:Also ich fand die Idee gut, so konzeptionös...
Also interessant sind solche dynamisch geladenen Scripte schon. Also wenn man sie lädt, dann sind alle Variablen nur lokal in der Ladefunktion vorhanden. Nach dem Laden hat man also nichts, worauf man zugreifen kann. Es sei denn, man schreibt die Ladefunktion so, dass sie ein ganz bestimmtes Objekt zurückgibt. Das ist natürlich nichts Globales, weil jeder Aufruf ein neues Objekt erzeugt.

Interessant ist auch folgendes Verhalten, z.B:

Code: Alles auswählen

import tkinter as tk

print(tk.BOTTOM)

def test():
    print(tk.TOP)

test()
Das war ein Test, ob sich in solch einem Script etwas Importiertes genauso verhält wie Variablen. Ja so ist es. Also die Variablen des Scripts sind script lokal, weil sie erstens nicht an die Ebene weitergegeben werden, welche die Ladefunktion aufruft. Zweiten gibt es da noch ein ungewohntes Verhalten. Das was außerhalb von Funktionen steht und man als global geneigt ist anzusehen, ist nämlich auch nicht modul global. Man kann auf solche Variablen auf der Scriptebene außerhalb von Definitionen zugreifen. Das gilt auch für etwas Importiertes.

So funktioniert print(tk.BOTTOM), weil es außerhalb einer Funktion aufgerufen wurde. Aber das print(tk.TOP) funktioniert nicht, da die Variablen außen nicht innen bekannt sind. Was außen ist, ist also auch lokal, Funktionen können keine anderen Funktionen aufrufen, da die auch nicht bekannt sind, es sei denn, man übergibt sie als Parameter.

Wenn man innerhalb einer Klasse, auf etwas außerhalb zugreifen will, muss es als Parameter übergeben werden, auch das tk für tkinter!

Es besteht also hier ein äußerst gekapseltes Verhalten, strenger als sonst, obwohl Code vielleicht so aussieht, als hätte man globale Variablen.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Freitag 28. April 2017, 22:40
von kbr
Alfons Mittelmeyer hat geschrieben:So funktioniert print(tk.BOTTOM), weil es außerhalb einer Funktion aufgerufen wurde. Aber das print(tk.TOP) funktioniert nicht, da die Variablen außen nicht innen bekannt sind.
Natürlich funktioniert dies, wie jeder leicht überprüfen kann. Dies entspricht auch der LGB-Regel — also keine Überraschung.

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Samstag 29. April 2017, 00:12
von Alfons Mittelmeyer
kbr hat geschrieben:
Alfons Mittelmeyer hat geschrieben:So funktioniert print(tk.BOTTOM), weil es außerhalb einer Funktion aufgerufen wurde. Aber das print(tk.TOP) funktioniert nicht, da die Variablen außen nicht innen bekannt sind.
Natürlich funktioniert dies, wie jeder leicht überprüfen kann. Dies entspricht auch der LGB-Regel — also keine Überraschung.
Dann teste mal, was da geht. Das wäre das, was geladen wird und soll heißen: test.py

Code: Alles auswählen

import tkinter as tk

print(tk.BOTTOM)

def test():
    print(tk.TOP)

test()
Und das ist das Main Script, welches dieses File lädt:

Code: Alles auswählen

def script_exec(filename):
    exec(compile(open(filename, "r").read(), filename, 'exec'))

script_exec('test.py')
Da erscheint die Fehlermeldung: NameError: name 'tk' is not defined

Das ist für python3. Probiere es aus, ich weiß wovon ich rede.

Und das funktioniert dann:

Code: Alles auswählen

import tkinter as tk

print(tk.BOTTOM)

def test(tk):
    print(tk.TOP)

test(tk)
Hier gibt es nichts Globales, ganz besonders nicht für das Main Script oder ein sonstiges Modul, welches das aufruft. Man kann aber einen returnwert zurückgeben, etwa:

Code: Alles auswählen

import tkinter as tk

print(tk.BOTTOM)

def test(tk):
    print(tk.TOP)

test(tk)

returnwert = tk.RIGHT
Und in diesem Zusammenhang:

Code: Alles auswählen

def script_exec(filename):
    exec(compile(open(filename, "r").read(), filename, 'exec'))
    return locals()['returnwert']

print(script_exec('test.py'))

Re: Was ist eine globale Variable und warum soll man sie nicht benützen?

Verfasst: Samstag 29. April 2017, 01:24
von BlackJack
Wenn `exec()` nicht sowieso schon etwas wäre was man nicht benutzen sollte wenn es da keinen richtig guten Grund gibt, dann schon gar nicht so das dieses überraschende Verhalten entsteht. Das muss man entweder *sehr* deutlich dokumentieren, oder die `script_exec()`-Funktion so schreiben das sich die Ausführung nicht so unerwartet verhält.