2017-07-26 65 views
1

我使用状态机python实现转换在“on_enter”回调中更改状态时的回调顺序

当我尝试直接在on_enter回调中更改机器的状态时,回调调用的顺序不是我所期望的。

请找到最小的可运行的代码如下,其中问题发生:

# coding: utf8 

"""Minimal script.""" 

from transitions.extensions import GraphMachine as Machine 

class MyStateMachine(object): 
    """My state machine""" 

    def __init__(self): 
     """Initialization.""" 
     super(MyStateMachine, self).__init__() 

     states = ["state_a", "state_b"] 
     transitions = [ 
      { 
       "trigger": "go_b", 
       "source": "state_a", 
       "dest": "state_b", 
       "before": "before", 
       "after": "after", 
      }, 
      { 
       "trigger": "go_a", 
       "source": "state_b", 
       "dest": "state_a", 
       "before": "before", 
       "after": "after", 
      }, 
     ] 

     self.__machine = Machine(self, states=states, transitions=transitions, 
           initial="state_a") 

    def before(self): 
     """Before transition.""" 
     print "before transition" 

    def after(self): 
     """After transition.""" 
     print "after transition - current state:", self.state 

    def on_enter_state_a(self): 
     """When entering in state A.""" 
     print "enter state A" 

    def on_exit_state_a(self): 
     """When exiting state A.""" 
     print "exit state A" 

    def on_enter_state_b(self): 
     """When entering in state A.""" 
     print "enter state B" 
     self.go_a() 

    def on_exit_state_b(self): 
     """When exiting state A.""" 
     print "exit state B" 


def main(): 
    """Main function.""" 
    machine = MyStateMachine() 
    machine.go_b() 

if __name__ == '__main__': 
    main() 

预期输出:

before transition 
exit state A 
enter state B 
after transition - current state: state_b 
before transition 
exit state B 
enter state A 
after transition - current state: state_a 

观察输出:

before transition 
exit state A 
enter state B 
before transition 
exit state B 
enter state A 
after transition - current state: state_a 
after transition - current state: state_a 

会不会是被视为一个bug ? 如果不是,我怎么能得到预期的输出?

回答

1

答:套机关键字queuedTrue

从过渡Readme

在转换的默认行为是立即处理事件。这意味着on_enter方法中的事件将在调用后绑定到回调函数之前被处理[...]如果启用了排队处理,则会在触发下一个转换之前完成转换:machine = Machine(states = states,queued = True)[...]

您需要将Machine初始化为queued=True。上面提到的部分涵盖了这两种情况下回调的执行顺序,并且在启用排队功能时还会改变Machine的行为。 我加queued作为关键字到您呈现的例子来说明这个过程:

from transitions.extensions import GraphMachine as Machine 


class MyStateMachine(object): 
    """My state machine""" 
    # added 'queued' to constructor of custom class... 
    def __init__(self, queued=False): 
     """Initialization.""" 
     super(MyStateMachine, self).__init__() 

     states = ["state_a", "state_b"] 
     transitions = [ 
      { 
       "trigger": "go_b", 
       "source": "state_a", 
       "dest": "state_b", 
       "before": "before", 
       "after": "after", 
      }, 
      { 
       "trigger": "go_a", 
       "source": "state_b", 
       "dest": "state_a", 
       "before": "before", 
       "after": "after", 
      }, 
     ] 
     # ... to pass the value to 'Machine' 
     self.__machine = Machine(self, states=states, transitions=transitions, 
           initial="state_a", queued=queued) 

    def before(self): 
     print "before transition" 

    def after(self): 
     print "after transition - current state:", self.state 

    def on_enter_state_a(self): 
     print "enter state A" 

    def on_exit_state_a(self): 
     print "exit state A" 

    def on_enter_state_b(self): 
     print "enter state B" 
     self.go_a() 

    def on_exit_state_b(self): 
     """When exiting state A.""" 
     print "exit state B" 


def main():  
    print "---- Standard behaviour ----" 

    machine = MyStateMachine() 
    machine.go_b() 

    print "---- Now queued ----" 

    queued_machine = MyStateMachine(queued=True) 
    queued_machine.go_b() 

if __name__ == '__main__': 
    main() 

输出:

---- Standard behaviour ---- 
before transition 
exit state A 
enter state B 
before transition 
exit state B 
enter state A 
after transition - current state: state_a 
after transition - current state: state_a 
---- Now queued ---- 
before transition 
exit state A 
enter state B 
after transition - current state: state_b 
before transition 
exit state B 
enter state A 
after transition - current state: state_a 

如果你不在意:转换支持logging

这样,你做不需要用打印语句混淆您的代码:

from transitions.extensions import GraphMachine as Machine 
import logging 


class Model(object): 

    def before(self): 
     pass 

    def after(self): 
     pass 

logging.basicConfig(level=logging.DEBUG) 

model = Model() 
machine = Machine(model, states=['A', 'B'], before_state_change='before', 
        after_state_change='after', initial='A') 
model.to_B() 

输出:

DEBUG:transitions.core:Initiating transition from state A to state B... 
DEBUG:transitions.core:Executed callback 'before' before transition. 
DEBUG:transitions.core:Exiting state A. Processing callbacks... 
INFO:transitions.core:Exited state A 
DEBUG:transitions.core:Entering state B. Processing callbacks... 
INFO:transitions.core:Entered state B 
DEBUG:transitions.core:Executed callback 'after' after transition.