嵌套在 Pytransitions 中
Nesting in Pytransitions
我一直在查看 github 上已解决的问题,SO,并通过谷歌搜索来解决这个问题。但我一直无法解决我的问题,这似乎是正确的地方。我已经在 github 上提出了一个问题,但我不确定这样做是否正确。
我正在制作一个可以包含多个子状态的状态机,这些子状态也是所有状态机。所以这基本上归结为根据 readme.
重用 HSM
我的最高等级SM是这样的:
from transitions.extensions import LockedHierarchicalMachine as Machine
from coordination.running import RunningStateMachine
logging.basicConfig(level=logging.ERROR)
logging.getLogger("transitions").setLevel(logging.INFO)
class RPPStateMachine(Machine):
def __init__(self, name):
self._running = RunningStateMachine()
self.name = name
states = [
"init",
{"name": "running", "children": self._running},
"stop",
]
Machine.__init__(self, states=states, initial="init")
self.add_transition("e_run", "init", "run", after=self.run_machine)
self.add_transition("e_stop", "*", "stop")
def run_machine(self):
self._running.initialize()
如您所见,状态机具有三个状态 init
、running
和 stop
。一旦事件 e_run()
通过类似
的方式发送
machine = RPPStateMachine("my_machine")
machine.e_run()
机器转换到 running
状态。
我以间接的方式进行,因为我希望事情自动发生。 e_run()
导致过渡到 running
,然后 run_machine
调用 运行 class 的 initialize
方法,该方法触发一个事件以启动事件链.下面我显示了 running
,这就清楚了。
所以运行状态定义为
from transitions.extensions import LockedHierarchicalMachine as Machine
from coordination.test_mode import TestingStateMachine
from coordination.release_mode import ReleaseStateMachine
class RunningStateMachine(Machine):
def __init__(self):
self._test_mode = TestingStateMachine()
self._release_demo = ReleaseStateMachine()
states = [
"init",
"configuration",
"idle",
{"name": "test_mode", "children": self._test_mode},
{"name": "release_mode", "children": self._release_mode},
]
Machine.__init__(self, states=states, initial="init")
self.add_transition("e_start_running", "init", "configuration", after=self.configuration)
self.add_transition("e_success_config", "configuration", "idle")
self.add_transition("e_test_mode", "idle", "test_mode")
self.add_transition("e_release_mode", "idle", "release_mode")
self.add_transition("e_start_running", "idle", "init")
def initialize(self):
print("Initialization step for running, emitting e_start.")
self.e_start_running()
def configuration(self):
print("Configuring...")
print( "Current state: " + self.state)
self.e_success_config()
与它的父类相似,由几个状态和几个子状态组成。
我还启用了日志记录以查看我进入和退出的状态。根据我的经验,嵌套状态机非常有用,因为您可以重用之前编写的状态。此外,随着状态机的增长,它有助于使事情更加模块化。所以没有一个国家变得巨大而难以read/understand。
所以不寻常的行为是,当调用 e_run()
时,我得到
的打印
INFO:transitions.core:Entered state running
INFO:transitions.core:Entered state running_init
Initialization step for running, emitting e_start.
INFO:transitions.core:Exited state init
INFO:transitions.core:Entered state configuration
Configuring...
current state: configuration
INFO:transitions.core:Exited state configuration
INFO:transitions.core:Entered state idle
如你所见
machine.state
>>> 'running_init'
而
machine._running.state
>>> 'idle'
我当然可以将转换定义移动到父状态,但这并不方便。我不能对所有子状态都这样做。显然,我希望每个子状态对其自己的行为负责。这里的常见做法是什么?这是错误还是预期行为?
如何巧妙地将状态机嵌套在彼此之下?
从 transitions
0.7.1 开始,将一个状态机作为另一个状态机的子级传递将 复制 所传递机器的所有状态到父级。通过的状态机保持不变(正如我们讨论的 here)。
from transitions.extensions import MachineFactory
HSM = MachineFactory.get_predefined(nested=True)
fsm = HSM(states=['A', 'B'], initial='A')
hsm = HSM(states=['1', {'name': '2', 'children': fsm}])
# states object have been copied instead of referenced, they are not identical
assert fsm.states['A'] is not hsm.states['2_A']
hsm.to_2_A()
# both machines work with different models
assert fsm.models[0] is not hsm.models[0]
assert fsm.state is not hsm.state
目前推荐的工作流程是拆分模型和机器,并将机器仅视为某种 'blueprint' 的父代:
from transitions.extensions import MachineFactory
class Model:
pass
HSM = MachineFactory.get_predefined(nested=True)
# creating fsm as a blueprint, it does not need a model
fsm = HSM(model=None, states=['A', 'B'], initial='A')
# use a model AND also
model = Model()
hsm = HSM(model=['self', model], states=['1', {'name': '2', 'children': fsm}])
# will only update the machine's state
hsm.to_1()
assert model.state != hsm.state
# will update ALL model states
hsm.dispatch("to_2_B")
assert model.state == hsm.state
但是,这并不能替代将机器正确隔离(and/or 范围)嵌套到父机器中。一项功能 draft 已创建,有望在可预见的未来实现。
我一直在查看 github 上已解决的问题,SO,并通过谷歌搜索来解决这个问题。但我一直无法解决我的问题,这似乎是正确的地方。我已经在 github 上提出了一个问题,但我不确定这样做是否正确。 我正在制作一个可以包含多个子状态的状态机,这些子状态也是所有状态机。所以这基本上归结为根据 readme.
重用 HSM我的最高等级SM是这样的:
from transitions.extensions import LockedHierarchicalMachine as Machine
from coordination.running import RunningStateMachine
logging.basicConfig(level=logging.ERROR)
logging.getLogger("transitions").setLevel(logging.INFO)
class RPPStateMachine(Machine):
def __init__(self, name):
self._running = RunningStateMachine()
self.name = name
states = [
"init",
{"name": "running", "children": self._running},
"stop",
]
Machine.__init__(self, states=states, initial="init")
self.add_transition("e_run", "init", "run", after=self.run_machine)
self.add_transition("e_stop", "*", "stop")
def run_machine(self):
self._running.initialize()
如您所见,状态机具有三个状态 init
、running
和 stop
。一旦事件 e_run()
通过类似
machine = RPPStateMachine("my_machine")
machine.e_run()
机器转换到 running
状态。
我以间接的方式进行,因为我希望事情自动发生。 e_run()
导致过渡到 running
,然后 run_machine
调用 运行 class 的 initialize
方法,该方法触发一个事件以启动事件链.下面我显示了 running
,这就清楚了。
所以运行状态定义为
from transitions.extensions import LockedHierarchicalMachine as Machine
from coordination.test_mode import TestingStateMachine
from coordination.release_mode import ReleaseStateMachine
class RunningStateMachine(Machine):
def __init__(self):
self._test_mode = TestingStateMachine()
self._release_demo = ReleaseStateMachine()
states = [
"init",
"configuration",
"idle",
{"name": "test_mode", "children": self._test_mode},
{"name": "release_mode", "children": self._release_mode},
]
Machine.__init__(self, states=states, initial="init")
self.add_transition("e_start_running", "init", "configuration", after=self.configuration)
self.add_transition("e_success_config", "configuration", "idle")
self.add_transition("e_test_mode", "idle", "test_mode")
self.add_transition("e_release_mode", "idle", "release_mode")
self.add_transition("e_start_running", "idle", "init")
def initialize(self):
print("Initialization step for running, emitting e_start.")
self.e_start_running()
def configuration(self):
print("Configuring...")
print( "Current state: " + self.state)
self.e_success_config()
与它的父类相似,由几个状态和几个子状态组成。 我还启用了日志记录以查看我进入和退出的状态。根据我的经验,嵌套状态机非常有用,因为您可以重用之前编写的状态。此外,随着状态机的增长,它有助于使事情更加模块化。所以没有一个国家变得巨大而难以read/understand。
所以不寻常的行为是,当调用 e_run()
时,我得到
INFO:transitions.core:Entered state running
INFO:transitions.core:Entered state running_init
Initialization step for running, emitting e_start.
INFO:transitions.core:Exited state init
INFO:transitions.core:Entered state configuration
Configuring...
current state: configuration
INFO:transitions.core:Exited state configuration
INFO:transitions.core:Entered state idle
如你所见
machine.state
>>> 'running_init'
而
machine._running.state
>>> 'idle'
我当然可以将转换定义移动到父状态,但这并不方便。我不能对所有子状态都这样做。显然,我希望每个子状态对其自己的行为负责。这里的常见做法是什么?这是错误还是预期行为?
如何巧妙地将状态机嵌套在彼此之下?
从 transitions
0.7.1 开始,将一个状态机作为另一个状态机的子级传递将 复制 所传递机器的所有状态到父级。通过的状态机保持不变(正如我们讨论的 here)。
from transitions.extensions import MachineFactory
HSM = MachineFactory.get_predefined(nested=True)
fsm = HSM(states=['A', 'B'], initial='A')
hsm = HSM(states=['1', {'name': '2', 'children': fsm}])
# states object have been copied instead of referenced, they are not identical
assert fsm.states['A'] is not hsm.states['2_A']
hsm.to_2_A()
# both machines work with different models
assert fsm.models[0] is not hsm.models[0]
assert fsm.state is not hsm.state
目前推荐的工作流程是拆分模型和机器,并将机器仅视为某种 'blueprint' 的父代:
from transitions.extensions import MachineFactory
class Model:
pass
HSM = MachineFactory.get_predefined(nested=True)
# creating fsm as a blueprint, it does not need a model
fsm = HSM(model=None, states=['A', 'B'], initial='A')
# use a model AND also
model = Model()
hsm = HSM(model=['self', model], states=['1', {'name': '2', 'children': fsm}])
# will only update the machine's state
hsm.to_1()
assert model.state != hsm.state
# will update ALL model states
hsm.dispatch("to_2_B")
assert model.state == hsm.state
但是,这并不能替代将机器正确隔离(and/or 范围)嵌套到父机器中。一项功能 draft 已创建,有望在可预见的未来实现。