Globale Variablen ja/nein

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
kiaralle
User
Beiträge: 216
Registriert: Donnerstag 19. August 2021, 19:11

Guten Morgen,

ich hatte mal gelesen, das globale Variablen zu vermeiden sind.

Wenn man aber einen Datensatz in einer Class oder Def erhebt und diesen im Programm permanent zur Verfügung stellen muss und es keine sicherheitsrelevanten Daten sind, was spricht dagegen?
Bisher habe ich aus Class und Def immer mit Rückgabewert gearbeitet..
Ich komme aber aktuell in Phasen wo globale Variablen mir praktischer erscheinen.
Oder schätze ich hier etwas falsch ein.

Globale Variablen können doch eigentlich nur zur Gefahr werden, wenn in einer anderen Funktion eine Variable erstellt wird die den selben Namen hat.
Also eindeutige Benennung der Variablen... Beispiel

global glob_variable

Gruß Ralf
Benutzeravatar
DeaD_EyE
User
Beiträge: 1371
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

kiaralle hat geschrieben: Mittwoch 5. August 2026, 07:16 Globale Variablen können doch eigentlich nur zur Gefahr werden, wenn in einer anderen Funktion eine Variable erstellt wird die den selben Namen hat.
Also eindeutige Benennung der Variablen... Beispiel

global glob_variable
Ja und nein.

Nein, wenn es sich um Objekte handelt, die unveränderbar sind. Das sind z.B. int, str, bytes, tuple.
Ja, wenn man Methoden veränderbarer Objekte aufruft wie z.B. append(element) bei einer Liste. Dann wird das Objekt modifiziert (nicht neu zugewiesen).

Wenn man global nicht nutzt, kann man dem globalen Namen kein neues Objekt zuweisen, kann aber das Objekt verändern, wenn es veränderbar (mutable) ist.

Es ist z.B. in Ordnung, wenn man Konstanten im Programm hat, auf die man lesend zugreift. Viele nutzen Klassen oder Enum für sowas.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
kiaralle
User
Beiträge: 216
Registriert: Donnerstag 19. August 2021, 19:11

Mein Gedanke war der, das ich dem User über ein Setupmenu eine Auswahl treffen lasse.
Motor und Geber, jeweils getrennt aus zwei SQLite-Tabellen.
An anderen Stellen benötige ich verschiedene Werte für Berechnungen aus diesen beiden Tabellen.
Ich merke mir die ID der beiden Datensätze global und kann somit im ganzen Programm sofor darauf zugreifen und in den Tabellen bestimmte Daten ziehen.
Wenn ich nicht global Variablen verwende, wüsste ich zu viel hin und her springen.

Ich glaube ich teste das mal so aus, geh in den Garten und mir fällt danach wieder was einfacheres ein. :-)
Jedenfalls lerne ich wieder etwas.
Benutzeravatar
Dennis89
User
Beiträge: 1747
Registriert: Freitag 11. Dezember 2020, 15:13

Das ist nicht robust, wenn man das allgemein betrachtet. Du arbeitest vermutlich mit einem User. Was ist wenn dass das Backend für eine Webanwendung wird und mehrere User eine Auswahl treffen?

Man kann Werte von Klassenattributen lesen, es muss nicht immer eine Methode sein, die per return etwas zurück gibt.

Ich würde es nicht mit globalen Variablen lösen. Zielführender wäre es, wenn du dir eine Möglichkeit erarbeitest, wie es "richtig" geht. Anhand der Auswahl würde ich vermutlich ein Objekt erstellen, dass die Auswahl enthält und das kann man dann herumreichen, lesen und vorallem kann man damit auch die Eingabewerte vallidieren.

Hast du ein Beispiel?
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
noisefloor
User
Beiträge: 4336
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Grundsätzlich: nein

Da hat auch nichts (und so rein gar nichts) mit "sicherheitsrelevant" zu tun. Du kommst in Python sowieso jederzeit an alles dran, egal ob lokal, global oder Attribute oder ... Globalen Variablen machen den Zustand des Programms einfach unübersichtlich, weil globalen Variablen im Prinzip jederzeit und überall geändert werden können.

Es gibt Anwendungsfälle, wo globale Variablen Sinn machen - klingt bei dir aber nicht so. Abgesehen von der Beschreibung an sich ist die Aussage "wo globale Variablen mir praktischer erscheinen." ein Indiz dafür, dass deine Programmstruktur wahrscheinlich verbessert werden könnte.

Gruß, noisefloor
kiaralle
User
Beiträge: 216
Registriert: Donnerstag 19. August 2021, 19:11

Dann mal Butter bei de Fisch :D

ich suche mir über die einzelnen Schritte den Motor und den Geber aus den zwei Tabelen aus der DB servo.

Tabelle motor = Motorhersteller, Motortyp, Motorpole
Tabelle geber = Hersteller, Model
Das funktioniet alles wunderbar über tkinter.

Ich erhalte eine ID vom Datensatz.
Die möchte ich weiter frei und jederzeit im Code verwenden.
Nur wo speichere ich die beiden IDs (Geber und Motor) ab?
Das mach ich jetzt aktuell über die globale Variaben motor_db_id und geber_id und lese ab und zu aus den zwei Tabellen.
Diese auslesen werde ich in diese Class Datenbank integrieren. Ist nicht das Problem.

Ich gehe in drei Jahren in Rente und möchte ein Prüfsystem für meine Kollegen hinterlassen. :)


Code: Alles auswählen




class Datenbank(object):
    def __init__(self, motorhersteller_combo, motorhersteller_var, motortyp_combo, motortyp_var, 
                 motorpolpaar_combo, motorpolpaar_var, geberhersteller_combo, geberhersteller_var,
                 gebertyp_combo, gebertyp_var,
                 geberdaten, conect_progress):
        self.motorhersteller_combo = motorhersteller_combo
        self.motorhersteller_var = motorhersteller_var
        self.motortyp_combo = motortyp_combo
        self.motortyp_var = motortyp_var
        self.motorpolpaar_combo = motorpolpaar_combo
        self.motorpolpaar_var = motorpolpaar_var
        self.geberhersteller_combo = geberhersteller_combo
        self.geberhersteller_var = geberhersteller_var
        self.gebertyp_combo = gebertyp_combo
        self.gebertyp_var = gebertyp_var
        self.geberdaten = geberdaten
        self.conect_progress = conect_progress
    

    
    def motorhersteller_sqlite(self):
        try:
            db_abfrage.execute("SELECT  DISTINCT  hersteller FROM motor")
            self.motorhersteller_combo['values'] = db_abfrage.fetchall()
        except verbindung.DatabaseError as error:
            print(error)        
        
        
        
    def motortyp_sqlite(self):
        try:
            db_abfrage.execute('SELECT typ FROM motor WHERE hersteller = ?' , (self.motorhersteller_var.get(),))
            self.motortyp_combo['values'] = db_abfrage.fetchall()
            

        except verbindung.DatabaseError as error:
            print(error)
            
            
    def motorpolpaar_sqlite(self):
        try:
            db_abfrage.execute('SELECT id,pole FROM motor WHERE typ = ?' , (self.motortyp_var.get(),))
            abfrage=db_abfrage.fetchall()
            self.motorpolpaar_combo['values'] = abfrage[0][1]
            #print(db_abfrage)
            global motor_db_id
            motor_db_id = abfrage[0][0]
        except verbindung.DatabaseError as error:
            print(error) 
        

 #Geberauswahl           
    def geberhersteller_sqlite(self):
        self.geberdaten.delete("1.0", END)
        try:
            db_abfrage.execute("SELECT  DISTINCT  hersteller FROM geber")
            self.geberhersteller_combo['values'] = db_abfrage.fetchall()
        except verbindung.DatabaseError as error:
            print(error)                    
            
    def gebertyp_sqlite(self):
        
        if self.geberhersteller_var.get() == "Sick":            
            self.gebertyp_combo['values'] = "Hiperface-Auto"
            self.geberdaten.insert('1.0', "Es wird nach einem Geber an \nSchnittstelle X gesucht und automatisch eingestellt")
            
            data = bytearray.fromhex("FF52")
            data.append(ChecksumXor8.calc(data))
            try:

                data = endat_data.send(data)
                response = endat_data.receive(7)
                if response.hex()[2:4] == "50" or  ChecksumXor8.calc(response) != 0:
                    error = sick_error.error(response.hex()[4:6])
                    print(error)
                    
                else:
                    model_id = response[3:4].hex()
                    
                    try:
                        db_abfrage.execute('SELECT * FROM geber WHERE model_id =?', (model_id,))
                        abfrage = db_abfrage.fetchall()
                        self.geberdaten.delete("1.0", END)

                    except verbindung.DatabaseError as error:
                        print(error)    
                        
            except Exception as e1:
                print ("error communicating...: " + str(e1))
                
        else:
            
            try:
                
                db_abfrage.execute('SELECT  model FROM geber WHERE hersteller = ?' , (self.geberhersteller_var.get(),))
                self.gebertyp_combo['values'] = db_abfrage.fetchall()
                db_abfrage.execute('SELECT * FROM geber WHERE hersteller = ?' , (self.geberhersteller_var.get(),))
                abfrage = db_abfrage.fetchall()

            except verbindung.DatabaseError as error:
                print(error)               
            
        
    
        datenkopf=["Typ:", "Datenverbindung:", "Model-ID:", "Sin-Cos / U:", "Singleturn:", "Multiturn:", "Speicher", "Hersteller:","Z-Spur:","DB-id:"]
                
        #datensatz=datenkopf[0],abfrage[0][1],"\n\r",datenkopf[1],abfrage[0][2]
        
        datensatz = "{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {} \n{} {}".format(datenkopf[0], abfrage[0][1], 
                            datenkopf[1] , abfrage[0][2], datenkopf[2] ,abfrage[0][3], 
                            datenkopf[3] ,abfrage[0][4], datenkopf[4] ,abfrage[0][5],
                            datenkopf[5] ,abfrage[0][6], datenkopf[6] ,abfrage[0][7],
                            datenkopf[7] ,abfrage[0][8], datenkopf[8] ,abfrage[0][9],
                            datenkopf[9] ,abfrage[0][0]
                            )
        
        global geber_db_id
        geber_db_id = abfrage[0][0]                 
        self.geberdaten.insert('1.0',datensatz) # Daten werden im Fenster Geberinfo angezeigt.

Die beiden ID sollen jetzt zum Bleistift hier in diese Class Hiperface einfließen.
Dann benötige ich keine der vielen Variablen und ich könnte aus der DB die verschiedenen Parameter der verschiedenen Geber ziehen.
Da stehen aktuell nur Testparameter drinnen die ich als "feste Variablen" da zur Verfügung stelle..

Code: Alles auswählen

class Hiperface(object):
    def __init__(self,polpaar,singleturn,multiturn, conect_progress, positions_value):
        self.polpaar = polpaar
        self.singleturn = singleturn
        self.multiturn = multiturn
        self.conect_progress = conect_progress
        self.positions_value = positions_value
        
    def position(self):

        data = bytearray.fromhex("FF42")
        data.append(ChecksumXor8.calc(data))
        try:
            data = endat_data.send(data)
            response = endat_data.receive(7)
            if response.hex()[2:4] == "50" or  ChecksumXor8.calc(response) != 0:
                error = sick_error.error(response.hex()[4:6])
                print(error)
                self.conect_progress.stop()

            else: 
                realposition = int.from_bytes(response[2:6],'big',signed=True)
#Prüfen start
                self.conect_progress.start()
                self.positions_value["text"] =  realposition                   
                schrittzahl_umdrehung_faktor = math.modf(realposition / self.multiturn)
                mech_winkel = round((360 / 1) * (schrittzahl_umdrehung_faktor[0])    )
                inkrement_teilung = round(self.multiturn / self.polpaar,2)
                offset_winkel = round(360/inkrement_teilung * realposition%360,2)
                #mech_winkel = round(360/max_inkrement * realposition,2)
# Prüfen ende                
            self.positions_value.after(100, self.position)    
                
            return realposition , mech_winkel, offset_winkel
        
        except Exception as e1:
            print ("error communicating...: " + str(e1))                    
    
        self.positions_value.after(10, self.position)    
    
    def resetposition(self):
        setposition ="00000000"
        
        data = bytearray.fromhex("FF 43" + setposition + "55")
        data.append(ChecksumXor8.calc(data))        
        try:
            data = endat_data.send(data)
            time.sleep(0.01)

            response = endat_data.receive(7)
            
            if response.hex()[2:4] == "50" or  ChecksumXor8.calc(response) != 0:
                error = "Fehler : " + sick_error.error("0f")
                print(error)
            else:
                info = "Phasenlage neu gesetzt "
                return info                 
        except Exception as e1:
            print ("error communicating...: " + str(e1))

kiaralle
User
Beiträge: 216
Registriert: Donnerstag 19. August 2021, 19:11

Wenn ich aber die class Datenbank als Anlaufstelle für alles nehme, dann weiß diese class über den aktuellen Motor und Geber bescheid und kann mit einfachen Return immer die Antworten geben.

Oder vergisst die class nach dem Verlassen die Daten?

Könnte gehen. Ich bastel und denke.
War nämlich gerade im Garten 😜
Benutzeravatar
noisefloor
User
Beiträge: 4336
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

genau genommen weiß die Klasse gar nichts, die ist nur die Grundlage. Die Daten sind in der jeweiligen Instanz der Klassen und ja, man beliebig viele Instanzen haben, die alle verschiedene Daten haben. Instanzen sind ja normalerweise an ein Objekt mit einem einmaligen Namen im aktuellen Namensraum gebunden. Und solange der Namensraum existiert (i.d.R. so lange das Skript läuft oder interaktive Interpreter, in dem die Klasse instanziert wurde) existieren die Daten.
Das sind (fortgeschrittene) Grundlagen, die man beim Umgang mit Klassen kennen sollte. Ggf. möchtest du nochmal dazu die passende Sektion im Python-Tutorial lesen.

Gruß, noisefloor
kiaralle
User
Beiträge: 216
Registriert: Donnerstag 19. August 2021, 19:11

Danke für die Erklärungen.
Ich denke ich weiß jetzt wie es gemacht werden sollte.
Antworten