在" on_enter"中更改状态时的回调顺序打回来

时间:2017-07-26 12:50:04

标签: python transitions

我使用状态机python实现过渡

当我尝试直接在 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

可能被认为是一个错误吗? 如果不是,我怎样才能获得预期的输出?

1 个答案:

答案 0 :(得分:1)

答案:将机器关键字queued设置为True

从转化Readme

  

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

您需要的是使用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

这样您就不需要使用print语句来混淆代码:

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.