while learning concepts of decorators in python came question if possible use decorators simulate state machine.
example:
from enum import enum class coffeemachine(object): def __init__(self): self.state = coffeestate.initial #@statemachine(shouldbe, willbe) @statemachine(coffeestate.initial, coffeestate.grounding) def ground_beans(self): print("ground_beans") @statemachine(coffeestate.grounding, coffeestate.heating) def heat_water(self): print("heat_water") @statemachine(coffeestate.heating, coffeestate.pumping) def pump_water(self): print("pump_water") class coffeestate(enum): initial = 0 grounding = 1 heating = 2 pumping = 3 so statemachine check if current state requested one, if is, should call underlying function , lastly should set state further.
how implement this?
sure can, provided decorator makes assumption state stored:
from functools import wraps class statemachinewrongstate(exception): def __init__(self, shouldbe, current): self.shouldbe = shouldbe self.current = current super().__init__((shouldbe, current)) def statemachine(shouldbe, willbe): def decorator(f): @wraps(f) def wrapper(self, *args, **kw): if self.state != shouldbe: raise statemachinewrongstate(shouldbe, self.state) try: return f(self, *args, **kw) finally: self.state = willbe return wrapper return decorator the decorator expects self passed in; i.e. should applied methods in class. expects self have state attribute track state machine state.
demo:
>>> cm = coffeemachine() >>> cm.state <coffeestate.initial: 0> >>> cm.ground_beans() ground_beans >>> cm.state <coffeestate.grounding: 1> >>> cm.ground_beans() traceback (most recent call last): file "<stdin>", line 1, in <module> file "<stdin>", line 6, in wrapper __main__.statemachinewrongstate: (<coffeestate.initial: 0>, <coffeestate.grounding: 1>) >>> cm.heat_water() heat_water >>> cm.pump_water() pump_water >>> cm.state <coffeestate.pumping: 3>
Comments
Post a Comment