@Danieldz: Irgendwie wird das einfach nur viel komplizierter ohne das es wirklich Vorteile bringt, dass Du Konstanten durch Zeichenketten ersetzen anhand derer dann die Konstanten ausgewählt werden. Was soll das?
`IO()` ist auch kein Name an dem ein Leser erkennen könnte das hier ein Pin aufgesetzt wird.
Warum importierst Du das Modul `GPIO_Hilfe` als `IO`? Wenn man die *eigenen* Module beim importieren umbenennt, stellt sich doch die Frage warum nicht gleich den Namen für das Modul verwendet unter dem man es dann benutzen will, denn man hat die Benennung des Moduls ja selbst in der Hand. Ich würde das aber auch nicht `IO` nennen, denn das ist viel zu generisch. Zudem gibt es in der Standardbibliothek bereits ein `io`-Modul.
Zur Namensschreibweise: Man schreibt Namen in Python klein_mit_unterstrichen. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (`MixedCase`).
Man sollte nichts abkürzen was nicht allgemein bekannt ist. Wenn man `bezeichnung` meint, sollte man nicht `bez` schreiben und `direction` statt `dir`. `HL`? Warum nennst Du ein Argument nach dem Spiel Half-Life?
Man vergleicht Wahrheitswerte nicht mit literalen Wahrheitswerten, denn da kommt ja nur wieder ein Wahrheitswert bei heraus. Entweder der, den man sowieso schon hatte, dann hätte man den auch gleich nehmen können, oder dessen Gegenteil, das man mit ``not`` bekommt. Also statt ``if warn == True:`` einfach nur ``if warn:``. Allerdings unterscheiden sich die beiden Zweige nur durch einen Wahrheitswert – und zwar genau den, den `warn` hat. Also kann man sich das ``if``/``else`` an der Stelle auch komplett sparen und einfach den Wert einsetzen:
Code: Alles auswählen
if warn == True:
gpio.setwarnings(True)
else:
gpio.setwarnings(False)
# ->
gpio.setwarnings(warn)
Da man die Warnungen aber sowieso nicht untersdrücken, sondern deren Ursache beheben sollte, ist dieser Teil der Funktion sowieso überflüssig.
`print()`-Ausgaben gehören nicht in solche Funktionen. Wenn man zur Fehlersuche Ausgaben braucht, dann gibt es dafür das `logging`-Modul, wo man dann auch entscheiden kann ob und was alles ausgegeben werden soll und wohin.
Die `setup()`-Funktion ist damit dann schon mal überflüssig, denn der Benutzer hat echt nix gewonnen wenn er statt ``gpio.setmode(gpio.BOARD)`` nun ``gpio_hilfe.setup('Board')`` schreibt. Zudem kann er auch ``gpio_hilfe.setup('Parrot')`` schreiben ohne dass das mit einem Fehler quittiert wird. Das ist also eher eine Verschlechterung.
Und das ist auch der Grund für den Fehler, denn bei der `io()`-Funktion gibst Du 'IN' an, was aber nicht 'In' ist und somit steht 'IN' für `gpio.OUT`, wie auch 'Parrot', 'Spam', 'Wombat', oder sonst was für `gpio.OUT` steht. Man sollte bei solchen Prüfungen immer explizit auf *alle* Werte prüfen, und nicht in einem ``else`` einfach annehmen, dass es schon der letzte verbleibende gültige Wert ist. In so ein ``else`` am Ende gehört Code der eine Ausnahme auslöst wenn kein gültiger Wert übergeben wurde.
Bei der `io`-Funktion verwendest Du das dritte Argument je nach dem was das zweite Argument war, für zwei unterschiedliche Dinge. Was es schwer bis unmöglich macht einen passenden Namen dafür zu finden. Und auch diese Funktion ersetzt eigentlich nur Zeichenketten durch Konstanten für den Aufruf. Die Funktion hat keinen Mehrwert, die macht einfach nur alles komplizierter und Fehleranfälliger. Um die tolle Verbesserung mal dem Original gegenüber zu stellen:
Code: Alles auswählen
gpio_hilfe.io(26, 'OUT', 'HIGH')
gpio_hilfe.io(21, 'IN', 'HIGH')
# ->
gpio.setup(26, gpio.OUT, initial=gpio.HIGH)
gpio.setup(21, gpio.IN, pull_up_down=gpio.PUD_UP)
Zum Programm: Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Die Kommentare sind allesamt überflüssig. Faustregel: Kommentare sollten nicht beschreiben *was* der Code tut, denn das steht da ja bereits als Code, sondern *warum* er das so tut – sofern das nicht offensichtlich ist.
Man sollte sicherstellen das die `cleanup()`-Funktion in jedem Fall aufgerufen wird. Und es wird dort ein nicht existierendes `n` übergeben.
Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt, die sie ausführen. `Taster` ist keine Tätigkeit. Von der Schreibweise des Namens würde der Leser hier keine Funktion sondern eine Klasse erwarten, die einen Taster repräsentiert. Da es hier keine gute/offensichtliche Beschreibung für die Tätigkeit gibt, kann man die Konvention `on_<ereignis>` verwenden, die für Rückruffunktionen nicht unüblich ist, also beispielsweise `on_button()`.
Magische Zahlen und insbesondere Wiederholungen davon vermeidet man mit Konstanten. Dann lässt sich am Code ablesen was die Zahl eigentlich bedeutet und wenn man sie Zahl an sich mal ändern muss, lässt sich das an *einer* Stelle im Code machen, statt Fehleranfällig alle Vorkommen suchen und ersetzen zu müssen.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
import time
from RPi import GPIO as gpio
BUTTON_PIN = 21
#
# TODO Find a better name that reflects what is driven by this pin.
#
OUTPUT_PIN = 26
def on_button(pin):
print('Pegelwechsel für Pin', pin)
def main():
gpio.setmode(gpio.BOARD)
try:
gpio.setup(OUTPUT_PIN, gpio.OUT, initial=gpio.HIGH)
gpio.setup(BUTTON_PIN, gpio.IN, pull_up_down=gpio.PUD_UP)
gpio.add_event_detect(BUTTON_PIN, gpio.BOTH)
gpio.add_event_callback(BUTTON_PIN, on_button)
time.sleep(10)
finally:
gpio.cleanup()
if __name__ == '__main__':
main()