Automaten programmieren
Wir wollen nun versuchen, mit dem gelernten Wissen um Automaten, einige Anwendungen mit Python zu programmieren. Wir programmieren also mit Zuständen und Zustandsübergängen.
- Zustand
- den Zustand können wir uns mit einer Variablen merken
- Zustandsübergang
- eine Aktion, z.B. ein Unterprogramm oder eine Funktion
- macht etwas und wechselt den Zustand
Enums
Wir könnten uns Zustände einfach mit einer int
-Variable merken. Dann müssen wir aber wissen, welche Zahl welchem Zustand entspricht. Für solche Zwecke gibt es die Klasse Enum
. Damit können wir eine Aufzählung von Werten erstellen und diesen sinnvolle Namen geben:
from enum import Enum
class Zustand(Enum):
LICHT_AUS = 1
LICHT_AN = 2
Wir erstellen eine eigene Klasse Zustand
die von Enum
erbt. Unsere Klasse definiert zwei konstante Werte: LICHT_AUS
und LICHT_AN
. Die Werte sind uns egal, müssen aber unterschiedlich sein!
Wir können nun über die Klasse Zustand
eine Variable auf diese vordefinierten Werte setzen und auch vergleichen:
...
zustand = Zustand.LICHT_AUS
def schalter_klick():
global zustand
if zustand is Zustand.LICHT_AUS:
zustand = Zustand.LICHT_AN
print("Licht eingeschaltet")
schalter_klick()
schalter_klick()
Aufgabe: Enums
Was müsste man im obigen Beispiel erweitern, damit das Licht wieder ausgeschaltet werden kann?
Getränkeautomat
Wir schauen das bereits bekannte Beispiel des Getraenkeautomates an. Zur Wiederholung nochmals das Zustandsübergangsdiagramm und die Zustandsübergangstabelle:
δ | 1.- | 2.- | sprite | coke |
---|---|---|---|---|
0.- | 1.- | 2.- | ||
1.- | 2.- | 3.- | ||
2.- | 3.- | |||
3.- | 0.- | 0.- |
Wir wollen diesen Automaten objektorientiert mit Python programmieren. Dazu brauchen wir also:
- ein Enum für die 4 Zustände
- die Klasse «Getränkeautomat»
- einen Startzustand
- 4 Methoden für die 4 Übergänge die beim Aufruf auch etwas ausgeben
- einige Tests, um zu schauen ob es funktioniert
Das Ergebnis könnte wie folgt aussehen:
from enum import Enum
class Zustand(Enum):
START = 1
BETRAG_1 = 2
BETRAG_2 = 3
BETRAG_3 = 4
class Getraenkeautomat:
def __init__(self):
self.zustand = Zustand.START
def eingabe_1(self):
if self.zustand is Zustand.START:
print("1.- eingegeben")
self.zustand = Zustand.BETRAG_1
elif self.zustand is Zustand.BETRAG_1:
print("1.- eingegeben")
self.zustand = Zustand.BETRAG_2
elif self.zustand is Zustand.BETRAG_2:
print("1.- eingegeben")
self.zustand = Zustand.BETRAG_3
else:
print("1.- kommt wieder raus")
def eingabe_2(self):
if self.zustand is Zustand.START:
print("2.- eingegeben")
self.zustand = Zustand.BETRAG_2
elif self.zustand is Zustand.BETRAG_1:
print("2.- eingegeben")
self.zustand = Zustand.BETRAG_3
else:
print("2.- kommt wieder raus")
def knopf_sprite(self):
if self.zustand is Zustand.BETRAG_3:
print("sprite kommt raus")
print("---")
self.zustand = Zustand.START
else:
print("nichts passiert")
def knopf_coke(self):
if self.zustand is Zustand.BETRAG_3:
print("coke kommt raus")
print("---")
self.zustand = Zustand.START
else:
print("nichts passiert")
Hinweis
Wir speichern den Betrag nicht als Zahl in einer Variablen, sondern der verfügbare Betrag entspricht einem Zustand.
Wir können nun einige Tests mit unserem Getränkeautomaten-Objekt anstellen und schauen, ob ein Sprite oder eine Cola rauskommt:
from getraenkeautomat import Getraenkeautomat
test = Getraenkeautomat()
test.eingabe_1()
test.eingabe_1()
test.eingabe_1()
test.knopf_coke()
test.eingabe_1()
test.eingabe_2()
test.eingabe_1()
test.knopf_sprite()
test.eingabe_2()
test.eingabe_2()
test.knopf_coke()
PythonKara
Kara gibt es auch in einer Python-Version:
https://www.swisseduc.ch/informatik/karatojava/pythonkara/index.html
Die Aufgaben sind ähnlich, man löst sie aber mit Python. Dabei kann man die Sensoren direkt abfragen. Je nach Aufgabe braucht es trotzdem Zustände!
Aufgabe: PythonKara
- Installiere und starte PythonKara
- Löse einige der eingebauten Aufgaben
- überlege dir, wie und wo du Zustände einsetzt
E-Mail-Checker
Bei einer Benutzereingabe soll der eingegebene Text auf ein gültiges E-Mail-Format überprüft werden. Dies kann mit einem speziellen endlichen Automaten, einem sogenannten Akzeptor erreicht werden:
Die vereinfachten Regeln lauten wie folgt:
- Gültige Zeichen: a-z und 0-9
- Reihenfolge
- Start mit mindestens einem Zeichen
- dann ein @
- wieder mindestens ein Zeichen
- dann ein Punkt
- nochmals mindestens ein Zeichen
also wäre z.B. ef2026@mygymer.ch eine gültige E-Mail-Adresse
Aufgabe: Zustandsübergangsdiagramm
Erstelle ein Zustandsübergangsdiagramm für die Reihenfolge der Zeichen einer E-Mail-Adresse:
- Zustände brauchst du um die Regeln überprüfen zu können
- Übergänge entsprechen den einzelnen Zeichen der E-Mail-Adresse
Lösung
Aufgabe: Python
Implementiere deinen Automaten in Python:
- schreibe ein Unterprogramm
check_email(adresse)
welches das Argumentadresse
auf gültiges E-Mail-Format überprüft - liefert
True
(gültig) oderFalse
(ungültig) - Teste dein Unterprogramm indem du vom Benutzer eingegebene E-Mail-Adressen überprüfst
Tipp: Zeichen-um-Zeichen
Ein String kann in einer for-Schleife Zeichen um Zeichen durchlaufen werden:
text = "Hallo"
for zeichen in text:
print(zeichen)
Tipp: Benutzereingaben
Ein vom Benutzer eingegebener String kann mit input()
eingelesen werden. Die Eingabe kann auch in einer Schleife wiederholt werden, optional auch mit Abbruch bei bestimmter Eingabe:
eingabe = ""
while eingabe != "x":
eingabe = input("bitte E-Mail-Adresse eingeben (x: Abbruch): ")
print(eingabe)