1

当转换从当前状态无效时,触发方法似乎仍在运行,然后引发 MachineError 异常。有没有办法阻止触发器的执行,以便对模型上的触发器的调用只会引发异常而不执行触发器?

抱歉,忘记提及使用_checked_assignment常见问题解答中的覆盖,这可能是导致此行为的原因。

from transitions import State, Machine

class StateMachine(Machine):

    def _checked_assignment(self, model, name, func):
        if hasattr(model, name):
            predefined_func = getattr(model, name)
            def nested_func(*args, **kwargs):
                predefined_func()
                func(*args, **kwargs)
            setattr(model, name, nested_func)
        else:
            setattr(model, name, func)

class Rocket(StateMachine):
    def __init__():
        StateMachine.__init__(
            self,
            states=["on_pad", "fueling", "ready", "launched", "meco", "second_stage", "orbit"],
            transitions=[
                {'trigger': 'fuel', 'source': 'on_pad', 'dest': 'fueling'},
                {'trigger': 'power_on', 'source': 'fueling', 'dest': 'ready'},
                {'trigger': 'launch', 'source': 'ready', 'dest': 'launched'}
            ],
            initial='on_pad'
        )

    def fuel():
        print("cryos loading...")

    def launch():
        print("launching")

def main():
    rocket = Rocket()
    rocket.launch()  # prints "launching" then throws Machine Error, need to block actual method execution
4

2 回答 2

0

在我输入示例时发现了问题,需要在_checked_assignment. 此方法应在常见问题解答中更新以保留原始转换功能。

    def _checked_assignment(self, model, name, func):
        if hasattr(model, name):
            predefined_func = getattr(model, name)
            def nested_func(*args, **kwargs):
                func(*args, **kwargs)  # need to call before pre-defined
                predefined_func()
            setattr(model, name, nested_func)
        else:
            setattr(model, name, func)
于 2021-09-15T19:24:13.087 回答
0

虽然您可以使用此Machine._checked_assignment答案中所述的覆盖来包装回调,但我建议将应在转换上下文中调用的方法与其回调绑定。可以在转换期间多次调用回调,如文档的回调执行顺序一章中所述。需要注意的是,回调不能与预期的触发器具有相同的名称,但这通常是一个小挫折,并且还允许您向同一事件添加多个回调。我修改了你的例子。充当有状态模型,但机器本身已分离。您还可以完全独立于您的RocketRocket如果您计划使用多个实例。一台机器可以处理多个有状态的对象。此外,我稍微重命名了您的回调并将它们传递给转换的before关键字。如前所述,这也可以是一个列表({'before': ['on_launch']}也是有效的)。这样,它们将在转换发生之前被调用,并且在 a)Rocket不处于正确状态或 b) 对相关转换的条件检查失败时不会被调用。

from transitions import Machine, MachineError


class Rocket:
    
    def __init__(self):
        self.machine = Machine(
            self,
            states=["on_pad", "fueling", "ready", "launched", "meco", "second_stage", "orbit"],
            transitions=[
                {'trigger': 'fuel', 'source': 'on_pad', 'dest': 'fueling', 'before': 'on_fueling'},
                {'trigger': 'power_on', 'source': 'fueling', 'dest': 'ready'},
                {'trigger': 'launch', 'source': 'ready', 'dest': 'launched', 'before': 'on_launch'}
            ],
            initial='on_pad'
        )

    def on_fueling(self):
        print("cryos loading...")

    def on_launch(self):
        print("launching")


rocket = Rocket()
try:
    rocket.launch()
    assert False
except MachineError:
    pass

rocket.fuel()  # >>> cryos loading...
rocket.power_on() 
rocket.launch()  # >>> launching
于 2021-09-16T06:58:47.247 回答