我最近在 Python 中发现了一个轻量级、面向对象的状态机实现,称为转换 ( https://github.com/pytransitions/transitions )。所以我尝试使用这些状态机,尤其是 HierarchicalGraphMachine。我想要的一个很好的功能是即使机器没有移动(保持相同的状态)也可以存储访问状态的历史记录。
而且从我从示例中看到的情况来看,我们实际上无法以简单的方式做到这一点,因为当机器状态未更改时before_state_change,并after_state_change没有调用 and。所以我们不能在这种情况下扩展我们的历史。为了解决这个问题,我最终创建了一个 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').
除此之外,通过设置ignore_invalid_triggers = False何时初始化Machine和使用该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 in the example) 或valid trigger but not reachable from the current state(call go() from state B) 引起的异常?
再次感谢你的帮助。