【发布时间】:2021-03-01 14:47:39
【问题描述】:
我最近在 Python 中发现了一个轻量级、面向对象的状态机实现,称为转换 (https://github.com/pytransitions/transitions)。所以我尝试使用这些状态机,尤其是 HierarchicalGraphMachine。我想要的一个很好的功能是即使机器没有移动(保持相同的状态),也可以存储访问状态的历史记录。
根据我从示例中看到的情况,我们实际上无法以简单的方式做到这一点,因为当机器状态未更改时,不会调用 before_state_change 和 after_state_change。所以我们不能在这种情况下扩展我们的历史。为了解决这个问题,我最终创建了一个 trigger_wrapper 函数:
def trigger_wrapper(self, trigger_name):
previous_state = self.state
result = None
try:
result = self.trigger(trigger_name)
except AttributeError as attribute_err:
print('Invalid trigger name: {}'.format(attribute_err))
except MachineError as machine_err:
print('Valid trigger name but not reachable: {}'.format(machine_err))
except Exception as err:
print('Cannot make transition with unknown error: {}'.format(err))
if result is False:
print('Trigger name reachable but condition(s) was not fulfilled')
....
current_state = self.state
# update history
.....
return result
然后,我们调用 trigger_wrapper 而不是 trigger:
before: machine.trigger('drink')
now: machine.trigger_wrapper('drink').
除此之外,通过在初始化Machine时设置ignore_invalid_triggers = False并使用这个trigger_wrapper函数,我们现在可以通过缓存异常知道机器无法移动的原因。
有没有更好的解决方案来持续跟踪访问状态?我认为另一种方法是覆盖触发功能,但由于NestedState,它似乎很复杂。
编辑 1(按照@aleneum 的建议)
感谢您的回复以及一个有趣的例子!!!
按照使用finalize_event 的示例进行操作。很顺利,但是这个回调函数似乎不足以捕捉到以下情况(我在代码中额外添加了2行):
... same setup as before
m.go()
m.internal()
m.reflexive()
m.condition()
m.go() # MachineError: "Can't trigger event go from state B!"
m.goo() # AttributeError: Do not know event named 'goo'.
>>> Expected: ['go', 'internal', 'reflexive', 'condition', 'go', 'goo']
>>> Expected: ['B', 'B', 'B', 'B', 'B', 'B']
换句话说,是否还有另一个回调可以捕获由调用invalid trigger(示例中为goo)或由valid trigger but not reachable from the current state(从状态B 调用go())引起的异常?
再次感谢您的帮助。
【问题讨论】:
标签: python transition pytransitions