分层状态机:嵌套机器上的on_enter调用父方法

时间:2017-08-07 11:50:41

标签: python transitions fsm

我正在使用pytransitions / transitions模块并尝试构建一些分层状态机。

在下面的代码段中,我触发了从一个嵌套状态到另一个嵌套状态的转换。

问题是如果我将on_enter回调附加到目标嵌套状态,则库正在父机器中搜索此回调。

from transitions.extensions import HierarchicalMachine as Machine
from transitions.extensions.nesting import NestedState as State

class Nested(Machine):
    def print_msg(self):
        print("Nested")
    def __init__(self):
        self.states = ['n1', {'name':'n2', 'on_enter':'print_msg'}]
        Machine.__init__(self, states=self.states, initial='n1')
        self.add_transition(trigger='goto_n2',
                            source='*',
                            dest='n2')

class Top(Machine):
    def print_msg(self):
        print("Top")
    def __init__(self):
        self.nested = Nested()

        self.states = [  't1',
                        {'name': 't2',
                        'children': self.nested}]
        Machine.__init__(self, states=self.states, initial='t1')
        self.add_transition(trigger='goto_t2',
                            source='*',
                            dest='t2_n1')



top_machine = Top()
top_machine.goto_t2()
top_machine.goto_n2()

脚本的输出是" Top"

如果我从Top类中删除print_msg(),那么我将获得AttributeError。

虽然理论上我可以在顶级机器中进行回调,但我绝对希望将我的状态和回调保持在嵌套机器的明确定义的边界内。

知道如何实现它吗?

1 个答案:

答案 0 :(得分:1)

来自相关的Github issue

字符串回调总是在模型中查找,在您的情况下是Top机器。 如果您没有将特定模型实例传递给Machine,它将作为模型本身。 对于更复杂的场景,我建议拆分机器(转换和相关规则) 和模型(基于实际状态的行为)。

当您将Machine实例传递给另一个HSM时,将复制规则和转换,而不仅仅是重复使用。这就是Nested将自己用作模型的原因,但嵌套版本将使用Top。只拥有Nested资产的副本有两个好处:第一,它不会干预原始的嵌套实例;第二,它允许重用核心提供的许多功能,否则必须重写并作为结果导致更高的代码复杂性。

最简单的'方法是通过引用而不是通过名称来传递回调。而不是' on_enter':' print_msg'使用' on_enter':self.print_msg。这样就可以解决回调引用,这会阻止转换在模型中查找(注意:在转换0.6.1 之前一直有错误)。

from transitions.extensions import HierarchicalMachine as Machine


class Nested(Machine):

    def __init__(self, parent):
        self.parent = parent
        states = ['1', {'name': '2', 'on_enter': self.print_msg}]
        transitions = [['finish', '*', '2']]
        super(Nested, self).__init__(states=states, transitions=transitions,
                                     initial='1')

    def print_msg(self):
        print("Nested")
        self.parent.print_top()


class Top(Machine):

    def print_msg(self):
        print("Top")

    def __init__(self):
        self.nested = Nested(self)

        states = ['A', {'name': 'B', 'children': self.nested}]
        transitions = [dict(trigger='print_top', source='*',
                            dest='=', after=self.print_msg),
                       dict(trigger='to_nested', source='*', 
                            dest='B_1')]

        super(Top, self).__init__(states=states, transitions=transitions,
                                  initial='A')

top_machine = Top()
top_machine.to_nested()
top_machine.finish()

如上所述,我还建议拆分机器和型号。这样,您可以使用MixIns来装饰主模型并使代码更加混乱。这样,您也可以使用OOP提供的每个工具来改变状态机的行为。