Pytransitions嵌套状态机中条件转换无法访问类属性的实现方案咨询
我帮你拆解下问题的核心,并分享几个无需传递参数的解决方案,先从最直接的修复说起:
问题根源:触发了错误的状态机事件
你的代码里有一个容易被忽略的细节:在NestedMachine.entry_initial中,你调用的是event_data.model.go(),但event_data.model指向的是父状态机MainMachine的实例。父状态机的go触发器是用来从initial切换到nested的,而此时父状态已经处于nested,所以这个触发器不会执行任何操作。你真正需要触发的是子状态机NestedMachine自身的go事件。
解决方案1:触发子状态机的事件(最推荐)
只需要把event_data.model.go()改成event_data.machine.go(),就能直接触发子状态机的go触发器:
def entry_initial(self, event_data): self._error = True event_data.machine.go() # 使用machine而非model,指向当前子状态机
这样修改后,条件方法error会正常访问到NestedMachine实例上最新的self._error值,状态会正确切换到nested_error,完全不需要传递任何参数。
其他无参数解决方案
方案2:通过event_data直接访问状态机属性
既然你已经在GenericMachine初始化时设置了send_event=True,条件方法可以直接通过event_data获取当前状态机实例,进而访问最新属性:
def error(self, event_data): # 直接从当前状态机实例获取_error,避免self绑定的潜在问题 return event_data.machine._error
这种方式不需要修改触发逻辑,只要调整条件方法的实现即可。
方案3:使用字符串形式的条件方法名
pytransitions支持用字符串指定条件方法名(动态解析),而非直接传递方法引用。修改NestedMachine的transitions定义:
transitions = [ { "trigger": "go", "source": "initial", "dest": "error", "conditions": "error", # 用方法名字符串代替self.error }, { "trigger": "go", "source": "initial", "dest": "done", "unless": "error", }, ]
这种方式下,pytransitions会在触发事件时动态查找并调用对应方法,确保访问到最新的属性值。不过要注意,当子状态机与父状态机共享model时,需要确保方法能被正确解析(这里你的error方法定义在NestedMachine中,子状态机处理条件时会优先查找自身的方法,所以可以正常工作)。
总结
最简洁的修复是修正触发事件的对象(用event_data.machine代替event_data.model),这也是最符合pytransitions嵌套状态机设计逻辑的方式。另外两种方案也能实现无参数的条件转换,可以根据你的代码结构选择适合的方式。
内容的提问来源于stack exchange,提问作者Jan Krejci

