Konstanten / globale Variablen überschreiben

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Hallo,

ich bin mir nicht sicher, was genau diese Variablen sind, Konstanten oder globale Variablen. Und zwar will ich auf dem Raspberry Pi ein Skript aktuell so umbauen, dass es seine Konfiguration aus einer Yaml-Datei liest und nicht mehr hart kodiert in dem Skript steht.

Hier ein verallgemeinerter Skript-Ausschnitt:

Code: Alles auswählen

import yaml

CONFIG_1 = ''
CONFIG_2 = ''

def init_config():
    configs = read_yaml('config/cfg.yml')
    CONFIG_1 = configs['config_1']
    CONFIG_2 = configs['config_2']

def read_yaml(yaml_file):
    with open(yaml_file) as cfg:
        return yaml.safe_load(cfg)

def do_something():
    # I'm using the CONFIG_1 and CONFIG_2 variable but it's empty

def main(prompt):
    try:
        init_script()
	do_something()
    except KeyboardInterrupt:
        pass
    finally:
        logging.info('Finishing script')
Wenn ich den Debugger durchlaufen lasse, dann sind in der Prozedur do_something die variable CONFIG_1 und CONFIG_2 leer. Obwohl die Werte richtig in configs stehen.

Was muss ich denn machen, um die Werte nicht in alle Prozeduren als Parameter geben muss, sondern sie in solche "globalen" (die skriptweit verfügbar sind) Variablen / Konstanten schreiben kann?

Vielen Dank und viele Grüße
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

Konstanten heißen so, weil sie konstant sind - also nie geändert werden.
Globale Variablen sind böse, die benutzt man nicht.

Lies deine Konfiguration in eine Datenstruktur und übergebe die an die Funktionen, die sie brauchen.
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Danke für deine Antwort.

Dann sind das tatsächlich Konstanten, danke. Dann werde ich es so machen, wie von dir beschrieben.
Benutzeravatar
sparrow
User
Beiträge: 4165
Registriert: Freitag 17. April 2009, 10:28

Das was du hast, sind aber keine Konstanten. Denn sie werden ja im Programm verändert. Das wäre also der klassische Fall einer globalen Variable.
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Ich bin jetzt doch noch auf ein Problem gestoßen. Wie löse ich denn folgendes:

In meinem Skript nutze ich mqtt. Wenn die Verbindung zum Broker hergestellt wurde, dann wird eine on_connect-Prozedur aufgerufen, um sich für ein best. Topic zu subscriben. Diese überschreibe ich in dem mqtt-Topic wie folgt:

Code: Alles auswählen

client.on_connect = on_connect

def on_connect(client, userdata, flags, rc):
    client.subscribe('my/mqtt/topic', 0)
Die Parameter, die daran übergeben werden bestimmte ich nicht selbst, sondern werden durch die client.on_connect-Prozedur bestimmt.

Kann ich dort ebenfalls die Konfigurationen aus der Konfigurationsdatei hineinbekommen? Ich möchte das Topic konfigurierbar machen. Dafür würde natürlich auch eine Konstante Sinn machen, aber ich stelle meinen Code in GitHub ein und, falls dieses jemand benutzen will, dann soll es so einfach wie möglich über die Konfigurations-Yml anpassbar sein, ohne im Code etwas ändern zu müssen.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das funktioniert auf verschiedene Arten. Eine ist functools.partial, aber noch üblicher wäre hier die Methode einer Klasse, die via reingereichter Konfiguration einfach das topic kennt, und sich entsprechend damit anmeldet.
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Vielen Dank für eure Antworten.
sparrow hat geschrieben: Sonntag 20. März 2022, 21:23 Das was du hast, sind aber keine Konstanten. Denn sie werden ja im Programm verändert. Das wäre also der klassische Fall einer globalen Variable.
Sorry, den Kommentar hatte ich übersehen. Überschrieben waren sie ja nur, weil ich bei der Überarbeitung des Skripts versucht habe, deren Werte zu ändern. Was aber nicht geklappt hat. ;)

__deets__ hat geschrieben: Sonntag 20. März 2022, 21:54 Das funktioniert auf verschiedene Arten. Eine ist functools.partial, aber noch üblicher wäre hier die Methode einer Klasse, die via reingereichter Konfiguration einfach das topic kennt, und sich entsprechend damit anmeldet.
functools.partial werde ich mir auf jeden Fall (versuchen zu) merken. In meinem Fall habe ich jetzt eine andere Lösung gefunden: In jede dieser überschriebenen Prozeduren wird ein userdata-Parameter mit reingegeben. Diese kann ich u.a. beim Initialisieren des Mqtt-Clients setzen, nachdem ich die Konfiguration ausgelesen habe. Dort hinein setze ich dann z.B. die Mqtt-Topic-Namen, die ich in den on_connect und on_message Prozeduren benötige.
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Vielen Dank für eure Antworten.
sparrow hat geschrieben: Sonntag 20. März 2022, 21:23 Das was du hast, sind aber keine Konstanten. Denn sie werden ja im Programm verändert. Das wäre also der klassische Fall einer globalen Variable.
Sorry, den Kommentar hatte ich übersehen. Überschrieben waren sie ja nur, weil ich bei der Überarbeitung des Skripts versucht habe, deren Werte zu ändern. Was aber nicht geklappt hat. ;)

__deets__ hat geschrieben: Sonntag 20. März 2022, 21:54 Das funktioniert auf verschiedene Arten. Eine ist functools.partial, aber noch üblicher wäre hier die Methode einer Klasse, die via reingereichter Konfiguration einfach das topic kennt, und sich entsprechend damit anmeldet.
functools.partial werde ich mir auf jeden Fall (versuchen zu) merken. In meinem Fall habe ich jetzt eine andere Lösung gefunden: In jede dieser überschriebenen Prozeduren wird ein userdata-Parameter mit reingegeben. Diese kann ich u.a. beim Initialisieren des Mqtt-Clients setzen, nachdem ich die Konfiguration ausgelesen habe. Dort hinein setze ich dann z.B. die Mqtt-Topic-Namen, die ich in den on_connect und on_message Prozeduren benötige.

Objektorientiert habe ich das ganze deshalb nicht gemacht, weil es in den ganzen Raspberry Pi-Forenbeiträgen, Tutorials,... die ich gelesen habe immer hieß, man solle den Raspberry Pi-Code als Skripte ohne Klassen, etc. schreiben. Bei mir nimmt das ganze auch nicht so eine Komplexität an, dass es ohne Objektorientierung unübersichtlich würde oder ich das Gefühl hätte, da groß Dinge kapseln zu müssen, etc.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was auch immer du da gelesen hast, ist großer Quatsch. Der Pi Code da draußen ist nahezu immer schlecht zusammengekloppt, und deckt auch nur absolut triviale Fälle ab. OO ist keine große Sache, und schon dein Beispiel rechtfertig das durchaus.
dirk1312
User
Beiträge: 19
Registriert: Dienstag 1. November 2016, 18:16

Danke für die Einschätzung. Grundsätzlich ist es ja wirklich keine große Sache, daraus ein paar Klassen, etc. zu machen. Dann werde ich erstmal die Konfigurationsgeschichte fertig machen und sicherstellen, dass die noch läuft. Danach werde ich es dann in OO umwandeln.
Antworten