2017-07-26 172 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.