Beim letzten Mal (Implementieren eines Modells mit Status und Verhalten (2)) haben wir "StopWatch" mit drei Status auf zwei Arten implementiert. .. Dieses Mal wird "StopWatch" mit * decorator * implementiert.
Beschreiben Sie zunächst den Zustandsübergang mit * decorator *. Es ist leichter zu verstehen, ob es sich um eine Zustandsübergangsmethode handelt.
from enum import auto
def transit(state):
def decorator(func):
def inner(self, *args, **kwargs):
self.start_stop, self.reset = self._TRANSIT[state]
func(self, *args, **kwargs)
return inner
return decorator
class StopWatch:
WAIT, PAUSE, MEASURE = auto(), auto(), auto()
def __init__(self):
self._TRANSIT = {StopWatch.WAIT: (self.start, lambda *args: None),
StopWatch.PAUSE: (self.start, self.reset_time),
StopWatch.MEASURE: (self.pause, lambda *args: None)}
self._TRANSIT_REVERSED = {v: k for k, v in self._TRANSIT.items()}
self.start_stop, self.reset = self._TRANSIT[StopWatch.WAIT]
@property
def state(self):
return self._TRANSIT_REVERSED[self.start_stop, self.reset]
@transit(MEASURE)
def start(self):
pass
@transit(PAUSE)
def pause(self):
pass
@transit(WAIT)
def reset_time(self):
pass
Versuchen Sie außerdem, die Zustandsübergangstabelle mit einem Dekorateur auszuschneiden. Der "Verhaltens" -Dekorator repräsentiert das Verhalten in einem bestimmten Zustand.
from enum import auto
from state_machine import behavior, transit
class StopWatch:
WAIT, MEASURE, PAUSE = auto(), auto(), auto()
def __init__(self):
self.state = StopWatch.WAIT
@behavior(WAIT, "start")
@behavior(MEASURE, "pause")
@behavior(PAUSE, "start")
def start_stop(self):
pass
@behavior(PAUSE, "reset_time")
def reset(self):
pass
@transit(MEASURE)
def start(self):
pass
@transit(PAUSE)
def pause(self):
pass
@transit(WAIT)
def reset_time(self):
pass
state_machine.py
from functools import wraps
def transit(state):
def decorator(func):
@wraps(func)
def inner(self, *args, **kwargs):
self.state = state
func(self, *args, **kwargs)
return inner
return decorator
def behavior(state, function):
def decorator(func):
@wraps(func)
def inner(self, *args, **kwargs):
if self.state == state:
getattr(self, function)(*args, **kwargs)
else:
func(self, *args, **kwargs)
return inner
return decorator
Obwohl davon ausgegangen wird, dass der Status in self.state beibehalten wird, kann derselbe * Dekorator * in anderen Modellen verwendet werden, sodass er als Modul state_machine
ausgeschnitten wurde.
Zum Zeitpunkt der Verarbeitung des Dekorateurs ist die Funktion noch nicht gebunden, sodass das Verhalten als Zeichenfolge angegeben wird. Sie können auch die Funktion __name__
verwenden, um zur Laufzeit eine gebundene Methode aufzurufen. (Nur zutreffende Teile sind unten gezeigt.)
Beachten Sie, dass ein * Dekorateur , der functools.wrap ()
nicht verwendet, nicht wie erwartet funktioniert. ( Decorator * schreibt die Funktion __name__
bei Verwendung von functools.wrap ()
nicht neu.)
state_machine.py
def behavior(state, function):
...
if self.state == state:
getattr(self, function.__name__)(*args, **kwargs)
...
...
@behavior(PAUSE, reset_time)
def reset(self):
pass
...