global vermeiden

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.
RedGargoyle
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2016, 13:12

@ DasIch
Puhh, ich glaube über die Antwort muss ich erst einmal meditieren :-)
Aber klar, kleckern mag ich echt nicht.

Trotzdem danke!


@ BlackJack
So langsam sehe ich ein, dass die Variante mit global bei Verschachtelungen zu sehr unübersichtlichem Code (und somit auch leicht zu Fehlern) führt.
Aber ich will trotzdem nochmal nachfragen: Gibt es, in der Form, in der ich die beiden Varianten angegeben habe, einen offensichtlichen Unterschied?
BlackJack

@RedGargoyle: Variante 1 ist offensichtlich schlechter als Variante 2, aus den ganzen Gründen aus denen ``global`` Böse™ ist.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

Um das Thema global (4.) aus dem Thread viewtopic.php?f=1&t=37842&start=30 noch zu beenden.
Habe nun auch noch den weiteren Ausdruck für Eigenschaften einer Klasse gefunden, nämlich Attribut.

Ich würde es nun mit einer sogenannten variablen Klasse lösen. Z.B.

Code: Alles auswählen

class VarHandler:
    def __init__(self):
        self.state1 = False
        self.state2 = False
        self.state3 = False
        self.var1 = None
   
variable = VarHandler()
variable.state1 = True
print variable.state1
Gibt es noch bessere Lösungen, oder findet ihr das gut?

Komisch, warum geht die Codebox nicht?
empty Sig
BlackJack

@harryberlin: Codebox ist gerade kaputt. :-(

Das was Du da jetzt geschrieben hast ist ja immer noch eine globale Variable, nämlich `variable`. Und ob das nun Sinn macht die Variablen als Attribute zu einem Objekt zusammen zu fassen hängt davon ab was die eigentlich bedeuten und ob die sinnvoll zusammengehören. Und wenn die zusammengehören, dann gibt es in der Regel auch Methoden die ebenfalls zu den Daten gehören.

Das was da steht kann man ohne Klasse und ohne globale Variablen so schreiben:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function


def main():
    state1 = False
    state2 = False
    state3 = False
    var1 = None

    state1 = True
    print(state1)


if __name__ == '__main__':
    main()
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

ja, ich brauche es auch global.
so besser?

Code: Alles auswählen

class VarHandler:
    def __init__(self):
        self.state1 = False
        self.state2 = False
        self.state3 = False
        self.var1 = None

variable = VarHandler()

def main():
    variable.state1 = True
    print variable.state1

if __name__ == 'main':
    main()
kann man in die klasse auch functionen für set und get einbauen, wo man direkt die variable als argument übergibt?
mir würde jetzt die möglichkeit einfallen, das argument variable als string zu übergeben und mit if zu parsen, aber geht das auch einfacher.
in etwa so:

Code: Alles auswählen

    def set(self,variable,value):
        self.variable = value

    def get(self,varaible):
        return self.variable
wobei, wäre eigentlich überflüssig. weil man die vars einfach mit = setzen oder holen kann.
empty Sig
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Das Problem an globalen Variablen ist nicht `global`, sondern dass sie eben globale Variablen sind.

Damit hat man das Problem, dass verschleiert wird wo der Wert geaendert wird und so der Code schwerer zu verstehen ist.
So wie es jetzt ist, ist es im Grunde _noch_ schlechter als mit `global`, weil dort wenigstens die Stellen deklariert werden, die den Wert aendern.

Die einzige Loesung zu dem Problem ist die Werte lokal zu erstellen und als Parameter an Funktionen zu uebergeben, die den geaenderten Zustand eventuell zurueckgeben.
Das ist allerdings ein Architekturproblem bei dem man ohne den verwendeten Aufbau und Code nicht konkret helfen kann.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

OK. D.h. wenn ich mit mehreren Funktionen arbeite, die unabhängig auf die variablen zugreifen müssen, dann ist global zulässig?
Denn der Zustand der Variable muss gepuffert werden. Und entsprechend welche funktion getriggert wird, muss sie abhängig von der variable agieren.

oder meinst du ich soll die variablen als argument für die funktion übergeben.
z.B.

Code: Alles auswählen

def (arg1, arg2, state1, state2, state3):
    #do all the things with the variables or change them
    .....
finde ich dann aber auch recht umständlich.
empty Sig
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@harryberlin: fünf Argumente für eine Funktion sind eigentlich eher selten. Wie die beste Lösung ist, ist, wie cofi schon geschrieben hat, aber von der konkreten Aufgabe ab. Bei so allgemeinen arg1, arg2 kann man halt nicht wirklich weiterhelfen.
BlackJack

@harryberlin: Gerade wenn mehrere Funktionen auf mehrere Variablen zugreifen ist ``global`` nicht zulässig, denn genau das ist doch das Chaos was man vermeiden möchte, wenn man das Programm verstehen möchte ohne wirklich immer das ganze Programm im Kopf zu haben weil man sonst nicht weiss welche Funktion von was abhängt und was ändert. Funktionen hat man doch um eine Einheit zu haben die man unabhängig vom Rest des Programms betrachten und nachvollziehen kann. Die man testen und wiederverwenden kann. Die man auch einfach in ein anderes Modul verlagern kann. Das geht alles nicht wenn man globalen Zustand berücksichtigen muss.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

@sirius3:
ich würde meinen code schon gern mal zeigen.
nur zeigte mir die erfahrung, dass mich das eher nicht zum ziel bringt.
denn mein code ist grottig, das weiß ich.
um ihn zu verbessern, bin ich ja hier. also muss ich leichte beispiele für teilabschnitte bringen.
anders sehe ich keinen weg. bzw. wird sich dem auch keiner annehmen.
und würde zu dem nicht in den thread hier passen, bzw. sprengen.

arg1, arg2 sind argumente für die funktion. state.. wären dann die globalen variablen.

jedoch was mir hilft, sind konkrete aussagen.
cofi hat geschrieben:
1. es ist schlimmer als global
2. als parameter übergeben
3. man müsste den code kennen
auf welche dieser aussagen beziehst du dich?

@blackjack:
ja, aber wenn die funktion durchlaufen ist, bleibt der zustand doch nicht erhalten.
oder liege ich da falsch?

z.B.

Code: Alles auswählen

def set_var(state):
    var = state

def get_var():
    return var
    
def main():
    set_var(True)
    print get_var()
    
if __name__='__main__':
    main()
       
das funktioniert doch nicht.
empty Sig
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@harryberlin: ich meinte die dritte Aussage. Wobei natürlich auch beide anderen Aussagen stimmen. Der Sinn einer Funktion ist es ja gerade, dass wenn sie durchlaufen ist, der Zustand auf seine Rückgabewerte reduziert wird. Damit kann man lesbaren, testbaren, wiederverwendbaren und funktionierenden Code schreiben.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

wo holt die get-funktion die variable dann her, wenn sie nicht durch parameterübergabe erzeugt werden kann?

z.B. ein licht_an. irgendwann später kommt ein event, mach_das_licht_aus. aber nur wenn das lichtanist.
das licht ist doch ein globaler zustand.
ist jetzt ein etwas blödes beispiel, weil man jetzt wieder sensoren einbauen kann, die abfragen ob das licht an ist.
gehen wir mal davon aus, es gibt nur den einen zustand.

oder vllt der zusatz, ich bin das licht.
empty Sig
BlackJack

@harryberlin: Man kann schlecht sinnvolle Vorschläge zum strukturieren von Code machen, dessen Semantik man nicht kennt. Niemand kann Dir bei so supergenerischen Namen wie arg1, var2, state3 und ohne die Operationen zu kennen, sagen wie man da was am besten zusammenfasst. Was man allgemein sagen kann, ist das globaler Zustand die ganzen bereits genannten Nachteile mit sich bringt.

Wenn eine Funktion Zustand ändern soll, dann muss sie entweder den Folgezustand zurückgeben, oder tatsächlich einen Zustand ändern, nur halt bitte keinen globalen und am besten dann auch nicht als Funktion, denn wenn sie einen Zustand ändert, gehört sie wahrscheinlich so eng zu dem Zustand, dass sie mit den Daten zusammen zu einem Objekt zusammengefasst werden könnte. Deine beiden Beispielfunktionen sind da etwas sinnfrei, also mal ein (total simples) Beispiel bei dem der Zustand verändert wird:

Code: Alles auswählen

def negate(state):
    return not state
   

def main():
    state = True
    state = negate(state)
    print state
Wieso sollte der Zustand nicht durch ein Argument übergeben werden können?
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

@blackjack
ich glaub so langsam fällt der groschen.
wenn ich die variablen in der main() drin setze, dann sollte es zulässig sein.
brauche dann halt einige threads, weil so vieles gleichzeitig läuft.
und übergabe müsste per argument(auch wenn es viele sind) erfolgen.

ich schick dir meine source mal per pn. aber bitte keine belehrungen ala style guide oder pep.
empty Sig
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
brauche dann halt einige threads, weil so vieles gleichzeitig läuft.
Bei Threads wird das aber viel komplizierter, weil man dann noch schwerer den Überblick behält, wann wer was ändert. Und eigentlich nimmt man Threads dann, wenn "Dinge" gleichzeitig, aber unabhängig voneinander laufen sollen.

_Welche_ Daten willst (musst?) du denn allen Threads verfügbar machen?
aber bitte keine belehrungen ala style guide oder pep.
Oh oh... mit der Einstellung kommst du hier nicht weit ;-)

Gruß, noisefloor
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

@noisefloor
wenn z.b. ein thread in einer while schleife ist, die beendet werden soll(ggf. auch durch nen anderen thread). dafür möchte ich die variable auf True setzen.
zum style guide und pep:
ja ich weiß, wer meine vorgeschichte nicht kennt, wird es als "assi" auffassen.
nur ich wurde schon zu genüge darauf hingewiesen.
Zuletzt geändert von harryberlin am Dienstag 9. Februar 2016, 22:19, insgesamt 1-mal geändert.
empty Sig
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@harryberlin: Threads dürfen gar keine Variablen teilen. Dafür gibt es spezielle Datenstrukturen (Events, Queues, Semaphoren).
BlackJack

@harryberlin: Ich habe mal kurz reingeschaut und kämpfe gerade damit nicht PEP8 als Lektüre zu empfehlen, denn das soll ich ja nicht. ;-) Ernsthaft, da ist mir zu viel ``global`` und zu viele Sternchen-Importe drin um mich damit näher auseinandersetzen zu wollen.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

oh wahnsinn. ich hab nen code der läuft, aber eigentlich absoluter schrott ist....
das wird ja ewig dauern, bis ich da was vernünftiges draus gemacht hab.
ewig, weil ich meine meiste zeit mit Brötchenverdienen verbringe.

ja, die sternchen...
ich werd echt mal schaun, dass ich ein py file mit klassen draus mache.
empty Sig
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

harryberlin hat geschrieben:oh wahnsinn. ich hab nen code der läuft, aber eigentlich absoluter schrott ist....
das wird ja ewig dauern, bis ich da was vernünftiges draus gemacht hab.
ewig, weil ich meine meiste zeit mit Brötchenverdienen verbringe.
Wie die meisten hier.

Es geht einfach darum, dass du dir dein Leben einfach machst, indem du Code schreibst, der einfach zu handhaben ist. Sternchen-Importe sind schlecht, weil dann nicht klar ist, welcher Name aus welchem Modul kommt. Wenn man dagegen Stenchen-Importe vermeidet und statt dessen explizit hinschreibt, welche Namen man importiert, sieht man sofort, wo ein Name herkommt und muss nicht raten.

Globale Variablen sind schlecht, weil man damit seinen Systemzustand über den gesamten Code verteilt. Übergänge von einem zu einem anderen Zustand können dann prinzipiell überall und zu jeder Zeit geschehen. Man muss also zB. bei jeder Zuweisung den gesamten Code im Kopf behalten, damit man alle Implikationen dieser Zuweisung verstehen kann. Insbesondere bei nebenläufigen Programmen ist das oft gar nicht möglich. Statt globale Variablen verwendet man dabei lieber Events oder Queues, die man den Threads bei der Initialisierung als Argumente übergibt. Darüber können dann die Threads kommunizieren, ohne dass ihnen irgendeine andere Codestelle ein Bein stellt.

Wirklich, es geht nicht darum, dass du Code schreibst, der irgendeinem abstrakten Schönheitsideal enspricht, bloß weil wir hier alle Ästheten sind, die aus bloßer Spießigkeit auf diesem Ideal beharren, sondern es geht darum, dass du dir dein Leben einfach machst.

Die Geschichte vom Metzger Ding aus dem Zhuangzi (AKA "Das wahre Buch vom Südlichen Blütenland") illustriert diesen Sachverhalt.

Ebenso "The Big Lebowski" von den Cohen-Brüdern.

Sagte ich bereits, dass du dir dein Leben einfach machen sollst?
In specifications, Murphy's Law supersedes Ohm's.
Antworten