【问题标题】:Hierarchical state machines: on_enter on nested machine calls parent methods分层状态机:嵌套机器上的 on_enter 调用父方法
【发布时间】:2017-08-07 11:50:40
【问题描述】:

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

在下面的 sn-p 中,我触发了从一个嵌套状态到另一个嵌套状态的转换。

问题是,如果我将 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。

虽然理论上我可以在顶级机器中拥有回调,但我肯定更愿意将我的状态和回调一起保存在嵌套机器的明确定义的边界中。

知道如何实现吗?

【问题讨论】:

    标签: python transitions fsm


    【解决方案1】:

    来自相关Githubissue

    字符串回调总是在模型中查找,在你的例子中是顶级机器。 如果您不将特定模型实例传递给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 提供的所有工具来改变状态机的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 2021-01-28
      • 1970-01-01
      • 1970-01-01
      • 2017-01-06
      • 1970-01-01
      相关资源
      最近更新 更多