Globale Namen definieren ???

Code-Stücke können hier veröffentlicht werden.
BlackJack

@lackschuh: Das ist immer noch alles sehr missverständlich formuliert. Was heisst zu Beginn des Programms? Im Quelltext auf Modulebene? Nein, da definiert man keine Variablen. Die Variable taucht auch nicht in mehreren Funktionen einfach so auf. Werte, ausser Konstanten, betreten Funktionen als Argumente. Welchen Wert der Name lokal dabei bekommt ist unabhängig davon an welchen Namen er bei einem Aufrufer gebunden ist.
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@lackschuh: Wenn die Variable nicht verändert wird oder wenn die Variable als gemeinsamer Startwert gilt, dann kann man sie situationsabhängig als Konstante definieren. Im Falle eines Startwertes sollte man den Startwert an einen neuen Namen binden und Veränderungen dann mit diesem neuen Namen durchführen. Zwar ist der neue Name zunächst nur eine Referenz auf das selbe Zahl-Objekt, welches auch von der Konstante referenziert wird, aber nach einer Rechenoperation wird ja ohnehin ein neues Zahl-Objekt als Resultat erzeugt und dieses wird dann halt neu an den zusätzlichen Namen gebunden (ich hoffe du kannst mir bis hier noch folgen). Somit kommt man gar nicht auf die Idee, irgendwas mit `global` hinzupfuschen. Wie gesagt: Das alles immer unter der Annahme, dass sich andere Funktionen ebenfalls nur für den Startwert und nicht für den veränderten Wert interessieren. Falls letzteres zutrifft, dann handelt es sich definitiv um keine Konstante, sondern um eine tatsächlich veränderliche Variable, dessen Definition man auf Modulebene vermeiden sollte.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Danke für die Infos.
Also zB habe ich Startwerte oder Flags, welche zu Beginn im Quelltext den Wert '''0''' haben. Wie könnte man es anhand des unteren Beispiels erklären, wie global zu vermeiden wäre?. Die Erklärung von snafu verwirrt mich leicht bzw. ich kapier sie wohl nicht ganz :K

Code: Alles auswählen

status = 0

class EmailThread(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        
    def run(self):
        global status
        while True:
		    #mach was
            if habe_mail == 1: # status wird auf 1 gesetzt
                status = 1
				
def main():
    global status
    while True:
        if status == 0:
            pass # mach nichts
        elif status = 1:
        # Aufruf weiterer Funktionen
Vielen Dank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Durch eine Queue-Objekt, welches du aus der main-Funktion dem E-Mail-Thread übergibst. Dann sparst du dir auch das Busy-Waiting und treibst deine Stromrechnung nicht in ungeahnte Höhen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

EyDu hat geschrieben:...sparst du dir auch das Busy-Waiting und treibst deine Stromrechnung nicht in ungeahnte Höhen.
Aber man bekäme doch einen Teil davon wieder herein durch die ansonsten anfallenden Heizkosten, die man sich dadurch spart. Ich meine, angesichts des Wetters heute...
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@lackschuh: Wie man das Beispiel am besten löst, hängt davon ab wie und was die beiden Threads eigentlich miteinander kommunizieren sollen. Ich sehe da denn Sinn von dem Flag nicht, beziehungsweise nicht wie man das mit vertretbarem Aufwand threadsicher hinbekommt ohne das der Thread der die Emails dann verarbeitet, den Test ob neue E-Mails vorhanden sind, nicht zumindest implizit noch man selber machen muss.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@lackschuh: je nach Anwendungsfall bekommst Du bei Deinem Ansatz Probleme, wenn mehr als eine Mail kommt. Wie läuft die Verarbeitung der Mails, wie wird der Inhalt von einem Thread zum anderen übertragen? Queues sind eine Möglichkeit, das sauber abzubilden.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@lackschuh:
Die Sinnhaftigkeit Deines Beispiels mal ausser Acht lassend hier das Beispiel ohne globale Variable und in threadsafe:

Code: Alles auswählen

# Weg damit, globals sind vorallem mit Threads Ausgeburten der Hölle!
# status = 0

class EmailThread(threading.Thread):
    
    def __init__(self, status):
        threading.Thread.__init__(self)
        self.status = status
        
    def run(self):
        #global status
        while True:
		    #mach was
            if habe_mail == 1: # status wird auf 1 gesetzt
                self.status.set()
				
def main():
    #global status
    # anstelle der globalen Variable nehmen wir eine threadsichere boolsche Variable.
    status = threading.Event()
    while True:
        if not status.is_set():
            pass # mach nichts
            # vllt. dem Teil ein sleep gönnen ;)
        #elif status = 1:
        # nix elif hier, da eh nur 1|0 unterschieden wird
        else:
            ...
        # Aufruf weiterer Funktionen
    ...
    # iwie fehlt noch der Aufruf des Mailthreads (am besten vor dem while, sonst wird das nie erreicht),
    # da kommt das Flag mit rein:
    emailthread = EmailThread(status)
    # und hier rennt er los ...
    emailthread.start()
BlackJack

@jerch: Ob das wirklich threadsafe (genug) ist kommt aber ganz darauf an was dieses Flag bedeutet und wer das wieder löscht.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

BlackJack hat geschrieben:@jerch: Ob das wirklich threadsafe (genug) ist kommt aber ganz darauf an was dieses Flag bedeutet und wer das wieder löscht.
Inwiefern könnte das Flag hier nicht threadsafe sein?
BlackJack

@jerch: Wie gesagt das kommt darauf an was das bedeutet und wer es wieder löscht und was zwischen Abgfragen und Setzen/Löschen auf den beiden Seiten passiert. Das Flag selber schützt ja nichts oder synchronisiert irgendwie vor gleichzeitigem verändern von gemeinsam benutzten Ressourcen. Zum Beispiel E-Mails auf einem Server, falls der Hauptthread das Flag als Anlass nimmt neue Mails zu verarbeiten. Wirklich sicher erscheint mir das nur wenn der Hauptthread das tatsächlich nur als Flag sieht das er nur liest, und bei dem es nichts ausmacht wenn er nicht alle Änderungen tatsächlich mitbekommt.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Hier noch ein aktuelles Beispiel, wo ich nicht weiss, wie ich es anders lösen soll.

Code: Alles auswählen

x = 150


@route('/home', method='GET')
def index():
    global x
    p = pipan.PiPan()
     
    if request.GET.get("right"):
        right = int(request.GET.get("right"))
        x = x - right
        print x
        p.do_pan(x)
Der Startwert ist 150 und von diesem Wert wird nach jedem Buttonkick 1 abgezogen. Mit jedem Klick wird aber die Funktion neu aufgerufen. Wie kann ich hier auf global verzichten?

mfg
BlackJack

@lackschuh: Ich würde mal behaupten der Code ist fehlerhaft weil er davon ausgeht, dass jede Webanfrage vom selben Prozess beantwortet wird, was man so allgemein nicht garantieren kann.

Man würde hier den Wert immer mit durch die Anfrage schleifen, oder in ein Cookie packen, oder ein Session-Cookie verwenden und den Wert in einer Datebank speichern wo man ihn mit Hilfe des Session-Cookie dem Client zuordnen kann.

Es sei denn der Wert ist tatsächlich global für alle Anfragen gültig, egal von welchem Client, dann kann der einfach so in die Datenbank.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Bei dem Beispiel geht es darum, zwei Servos, auf welchen eine Kamara montiert ist, horizontal und vertikal zu steuern. 150 ist Mitte laut pipan-Doku. Wäre eine DB in diesem Fall nicht 'overpowered'?
BlackJack

@lackschuh: Würde ich nicht sagen. Bevor man selber etwas schreibt was die Daten persistent und sicher/konsistent bei nebenläufigem Zugriff speichert, kann man auch gleich eine Datenbank verwenden. Weniger potential etwas falsch zu machen und letztendlich wohl auch einfacher zu benutzen als sich so etwas selber zu schreiben. Man muss ja keine Oracle Enterprise Datenbank aufsetzen, SQLite3 tut's ja auch.

Andererseits könnte es Sinn machen die Servosteuerung in einen eigenen Server zu stecken um damit zu erzwingen dass das Gerät immer nur von einem Prozess aus angesteuert wird. Dann könnte sich dieser Prozess auch den aktuellen Zustand merken und ihn abfragbar machen.
Antworten