使用装饰器实现状态机

时间:2015-07-13 14:58:21

标签: python python-3.x decorator state-machine python-decorators

在python中学习装饰器的概念时,我想到了是否可以使用装饰器来模拟状态机。

示例:

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

所以状态机所做的就是检查我的当前状态是否是请求的状态,如果是,它应该调用底层函数,最后应该进一步设置状态。

你会如何实现这个?

1 个答案:

答案 0 :(得分:1)

当你的装饰者假设状态存储在哪里时,你肯定可以:

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

装饰者希望传递self;即它应该适用于一个类中的方法。然后,它希望self具有state属性来跟踪状态机状态。

演示:

>>> 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>