try: except: else: liefert Variable nicht zurück
Verfasst: Freitag 14. Juli 2023, 18:29
Liebe Python-Gemeinde,
ich habe hier ein Python-Problem, für das ich keine Lösung und auch kein work-around finde. Das Programm wird auf einem RPi 4, Model B Rev1.4 ausgeführt, Python Version ist 3.11.4.
Hintergrund: In dieser Anwendung schaltet das RPi Ausgänge über ein externes MCP23017, Verbindung über I²C, verwendete Bibliothek adafruit_mcp230xx.mcp23017.
Einer der Ausgänge ist ein Leistungschütz. Sporadisch gibt es Fehler in der Kommunikation über I²C, offenbar durch elektromagnetische Störungen. Entstörmaßnahmen (Varistor pp) sind durchgeführt.
Eine einfache und zuverlässige Behebung des Problems bietet Pythons try: except: else:
def PA1_ein():
try:
PA1.value = True # setze Ausgang PA1
except:
time.sleep(0.3) # im Störungsfall warte 300ms und versuche es erneut
PA1_ein()
else:
return # im Erfolgsfall zurück zur aufrufenden Routine
Nun möchte man vielleicht wissen, wie oft solche Störungen aufgetaucht sind und wie lange sie gedauert haben. Ich habe daher einen Fehlerzähler k eingeführt, der sich aber leider nicht so verhält, wie ich es erwarte: Der Zähler wird nämlich nicht an das aufrufende Programm zurückgeliefert, stattdessen ein None.
Zur Erläuterung ein Schnipsel des aufrufenden Programms:
k = 55
…
print("vor PA1_ein", k) # Zähler ausgeben
k = Bibl.PA1_ein(k) # PA1 einschalten
print("nach PA1_ein", k, type(k)) # Zähler ausgeben
…
und ein Schnipsel des ausführenden Programms:
def Störung(k):
time.sleep(0.3) # Warte
print(bcolors.RT + "Störung" + bcolors.RESET, k) # Ausgabe in rot
k += 1 # Zähler inkrementieren
print("in Störung", k)
return k
def PA1_ein(k):
print("vor try", k)
try: # setze Ausgang auf True
PA1.value = True
print("in try", k)
except:
k = Störung(k) # Störung erkannt, Modul Störung aufrufen
print("in except", k) # erneut versuchen
PA1_ein(k)
else:
print("in else", k, type(k))
return k # im Erfolgsfall zurück mit Zählerstand
Das Verhalten des Fehlerzählers k bei Störung ist hier dargestellt:
vor PA1_ein 55 # vor Aufruf des Moduls ist der Zähler 55 (voreingestellt)
vor try 55 # im Unterprogramm, vor try: ist der Zähler 55
Störung 55 # Ausgabe im Modul Störung, Zähler 55
in Störung 56 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler 56
in except 56 # zurück im Unterprogramm, except: Zähler 56
vor try 56 # erneuter Aufruf des Unterprogramms: Zähler 56
Störung 56 # Störung liegt noch an: Ausgabe im Modul Störung, Zähler 56
in Störung 57 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler nun 57
vor try 57 # im Unterprogramm, vor try: ist der Zähler 57
Störung 57 # Störung liegt noch an: Ausgabe im Modul Störung, Zähler 57
in Störung 58 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler 58
in except 58 # zurück im Unterprogramm, except: Zähler 58
vor try 58 # erneuter Aufruf des Unterprogramms: Zähler 58
in try 58 # Störung liegt nicht mehr an, try ist erfolgreich, Zähler 58
in else 58 <class 'int'> # in else wird das Unterprogramm verlassen, Zähler 58
nach PA1_ein None <class 'NoneType'> # nach Rückkehr ins aufrufende Programm ist der Zähler None
Für eine Erläuterung des Fehlverhaltens bin ich sehr dankbar.
Beste Grüße
Peter
ich habe hier ein Python-Problem, für das ich keine Lösung und auch kein work-around finde. Das Programm wird auf einem RPi 4, Model B Rev1.4 ausgeführt, Python Version ist 3.11.4.
Hintergrund: In dieser Anwendung schaltet das RPi Ausgänge über ein externes MCP23017, Verbindung über I²C, verwendete Bibliothek adafruit_mcp230xx.mcp23017.
Einer der Ausgänge ist ein Leistungschütz. Sporadisch gibt es Fehler in der Kommunikation über I²C, offenbar durch elektromagnetische Störungen. Entstörmaßnahmen (Varistor pp) sind durchgeführt.
Eine einfache und zuverlässige Behebung des Problems bietet Pythons try: except: else:
def PA1_ein():
try:
PA1.value = True # setze Ausgang PA1
except:
time.sleep(0.3) # im Störungsfall warte 300ms und versuche es erneut
PA1_ein()
else:
return # im Erfolgsfall zurück zur aufrufenden Routine
Nun möchte man vielleicht wissen, wie oft solche Störungen aufgetaucht sind und wie lange sie gedauert haben. Ich habe daher einen Fehlerzähler k eingeführt, der sich aber leider nicht so verhält, wie ich es erwarte: Der Zähler wird nämlich nicht an das aufrufende Programm zurückgeliefert, stattdessen ein None.
Zur Erläuterung ein Schnipsel des aufrufenden Programms:
k = 55
…
print("vor PA1_ein", k) # Zähler ausgeben
k = Bibl.PA1_ein(k) # PA1 einschalten
print("nach PA1_ein", k, type(k)) # Zähler ausgeben
…
und ein Schnipsel des ausführenden Programms:
def Störung(k):
time.sleep(0.3) # Warte
print(bcolors.RT + "Störung" + bcolors.RESET, k) # Ausgabe in rot
k += 1 # Zähler inkrementieren
print("in Störung", k)
return k
def PA1_ein(k):
print("vor try", k)
try: # setze Ausgang auf True
PA1.value = True
print("in try", k)
except:
k = Störung(k) # Störung erkannt, Modul Störung aufrufen
print("in except", k) # erneut versuchen
PA1_ein(k)
else:
print("in else", k, type(k))
return k # im Erfolgsfall zurück mit Zählerstand
Das Verhalten des Fehlerzählers k bei Störung ist hier dargestellt:
vor PA1_ein 55 # vor Aufruf des Moduls ist der Zähler 55 (voreingestellt)
vor try 55 # im Unterprogramm, vor try: ist der Zähler 55
Störung 55 # Ausgabe im Modul Störung, Zähler 55
in Störung 56 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler 56
in except 56 # zurück im Unterprogramm, except: Zähler 56
vor try 56 # erneuter Aufruf des Unterprogramms: Zähler 56
Störung 56 # Störung liegt noch an: Ausgabe im Modul Störung, Zähler 56
in Störung 57 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler nun 57
vor try 57 # im Unterprogramm, vor try: ist der Zähler 57
Störung 57 # Störung liegt noch an: Ausgabe im Modul Störung, Zähler 57
in Störung 58 # Ausgabe im Modul Störung, nach Inkrementierung ist der Zähler 58
in except 58 # zurück im Unterprogramm, except: Zähler 58
vor try 58 # erneuter Aufruf des Unterprogramms: Zähler 58
in try 58 # Störung liegt nicht mehr an, try ist erfolgreich, Zähler 58
in else 58 <class 'int'> # in else wird das Unterprogramm verlassen, Zähler 58
nach PA1_ein None <class 'NoneType'> # nach Rückkehr ins aufrufende Programm ist der Zähler None
Für eine Erläuterung des Fehlverhaltens bin ich sehr dankbar.
Beste Grüße
Peter