如果转换无效,是否可以阻止触发器的执行?
Is it possible to block execution of a trigger if the transition isn't valid?
似乎触发方法仍然 运行 然后在从当前状态转换无效时引发 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
在我输入示例时发现问题,需要在 _checked_assignment
内的 predefined_func() 之前调用传入的 func()。此方法应在 FAQ 上更新以保留原始转换功能。
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)
虽然您可以按照 answer, I'd recommend tying methods that should be called in the context of a transition to its callbacks. Callbacks can be called on multiple occasions during a transition as described in the documentation's chapter Callback execution order 中的描述使用 Machine._checked_assignment
的覆盖来包装您的回调。需要注意的是,回调不能与预期的触发器同名,但这通常是一个小挫折,并且还可以让您向同一事件添加多个回调。我稍微修改了你的例子。 Rocket
充当有状态模型,但机器本身已分离。如果您计划使用多个实例,您还可以完全独立于 Rocket
管理状态机。一台机器可以处理多个有状态对象。此外,我稍微重命名了您的回调并将它们传递给转换的 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
似乎触发方法仍然 运行 然后在从当前状态转换无效时引发 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
在我输入示例时发现问题,需要在 _checked_assignment
内的 predefined_func() 之前调用传入的 func()。此方法应在 FAQ 上更新以保留原始转换功能。
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)
虽然您可以按照 Machine._checked_assignment
的覆盖来包装您的回调。需要注意的是,回调不能与预期的触发器同名,但这通常是一个小挫折,并且还可以让您向同一事件添加多个回调。我稍微修改了你的例子。 Rocket
充当有状态模型,但机器本身已分离。如果您计划使用多个实例,您还可以完全独立于 Rocket
管理状态机。一台机器可以处理多个有状态对象。此外,我稍微重命名了您的回调并将它们传递给转换的 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