如果您愿意在每个周期(重新)进入状态,这应该可以解决问题:
from transitions import Machine
from random import choice
class Model(object):
def on_enter_manual(self):
# do_user_input_actions()
print('manual')
def on_enter_auto(self):
# do_automatic_actions()
print('auto')
def event_detected(self):
# return gpio.event_detected()
# For simulation purposes randomise the return value
return choice([True, False])
states = ['manual', 'auto']
transitions = [{'trigger': 'loop', 'source': ['manual', 'auto'],
'dest': 'manual', 'conditions': 'event_detected'},
{'trigger': 'loop', 'source': ['manual', 'auto'],
'dest': 'auto'}]
model = Model()
machine = Machine(model=model, states=states,
transitions=transitions, initial='manual')
for i in range(10):
model.loop()
transitions 按添加顺序处理可能的转换。这意味着当event_detected 返回True 时执行第一个转换。如果不是这种情况,将选择第二个转换,因为它没有条件。
对于这个解决方案,可以进行一些调整:
a) 您可以将 source:[..] 替换为 source:'*' 以允许从所有状态进行循环转换。如果您想在将来添加状态,这可能很有用,但如果您打算使用多个触发器,它也可能适得其反。
b) 如果do_user_input_actions、gpio.event_detected、do_automatic_actions 是静态方法,您可以通过使用以下转换或多或少地省略模型:
transitions = [{'trigger': 'loop', 'source': ['manual', 'auto'],
'dest': 'manual', 'conditions': gpio.event_detected,
'after': do_user_input_actions},
{'trigger': 'loop', 'source': ['manual', 'auto'],
'dest': 'auto', 'after': do_automatic_actions}]
machine = Machine(states=states, transitions=transitions, initial='manual')
请注意,我传递的是函数引用而不是字符串。字符串被认为是模型函数,而函数引用可以来自任何地方。由于我们的模型或多或少是空的,我们可以使用Machine 实例作为模型。仅当行为相当简单时才建议这样做。专用模型使处理复杂配置更易于维护。我将函数回调传递给after,但在这种情况下,不管是在状态转换之前、期间还是之后执行。
为了完整起见,并且由于您明确提到您不想在转换期间处理用户输入,我建议采用Strategy Pattern 方法,在该方法中我们创建可以以相同方式处理的策略对象,但执行不同的任务.
只要状态发生变化,策略就会被替换。这次我们需要 unless 在第二次转换中仅在未检测到用户输入时进入“自动”模式(unless 只是 conditions 的便利对应物)。我们还使用了Machine 的关键字finalize_event,无论先前尝试的转换是否成功,它都会始终执行一个函数。我们也可以自己拨打Model.execute:
from transitions import Machine
from random import choice
class AutoStrategy(object):
def execute(self):
# do_automatic_actions()
print('auto')
class UserInputStrategy(object):
def execute(self):
# do_user_input_actions()
print('manual')
class Model(object):
def __init__(self):
self.strategy = UserInputStrategy()
def execute(self):
self.strategy.execute()
def on_enter_manual(self):
# We could use a singleton here if *Strategy is stateless
self.strategy = UserInputStrategy()
def on_enter_strategy(self):
self.strategy = AutoStrategy()
def event_detected(self):
# return gpio.event_detected()
# For simulation purposes, randomise the return value
return choice([True, False])
states = ['manual', 'auto']
transitions = [{'trigger': 'loop', 'source': 'auto', 'dest': 'manual',
'conditions': 'event_detected'},
{'trigger': 'loop', 'source': 'manual', 'dest': 'auto',
'unless': 'event_detected'}]
model = Model()
machine = Machine(model=model, states=states, transitions=transitions,
initial='manual', finalize_event='execute')
for i in range(10):
model.loop()