2017-04-05 20 views
0

我目前动态创建使用tyarkoni/transitions为Python状态机。但是,我已经到了一个我想重新命名一个状态并且是转换的地步。我想知道是否有办法做到这一点,而不用删除并重新添加一个不同的名称状态。重命名状态和转移已应用于计算机

更具体地说,我做的是我创建的状态和转换,同时通过一个未知的系统做一个BF-搜索与一组子系统和实际名称/状态的IDS /系统有时可在搜索的后期阶段被“发现”,而不是在状态被找到并被添加到状态机时(然后被保存在临时名称/ ID下)。然后我想在程序的其他部分重新命名它们以便于处理等。

有没有简单的方法来做到这一点?

如何,我认为是上面是在Python执行你就可以重命名状态

from transitions import Machine 
s = ['A','B','C'] # States 
t = [['ab','A','B'],['bc','B','C'],['ca','C','A']] # Transitions 
m = Machine(states=s,transitions=t,initial='A') 
m.state # Current state ('A') 
m.get_state('A') # Gets state 'A' (<State('A')@140486642630440>) 
m.get_state('A').name # Gets state name 'A' ('A') 
m.get_state('A').name = 'D' # Renames state name 'A' to 'D' 
m.get_state('A') # Gets state 'A' (<State('D')@140486642630440>) 
m.get_state('A').name # Gets state name 'A' ('D') 
# The following generates an error, since the state isn't renamed in the machine 
m.get_state('D') # (ValueError: State 'D' is not a registered state.) 

结果实例

>>> from transitions import Machine 
>>> s = ['A','B','C'] # States 
>>> t = [['ab','A','B'],['bc','B','C'],['ca','C','A']] # Transitions 
>>> m = Machine(states=s,transitions=t,initial='A') 
>>> m.state # Current state ('A') 
'A' 
>>> m.get_state('A') # Gets state 'A' (<State('A')@140486642630440>) 
<State('A')@140329230661784> 
>>> m.get_state('A').name # Gets state name 'A' ('A') 
'A' 
>>> m.get_state('A').name = 'D' # Renames state name 'A' to 'D' 
>>> m.get_state('A') # Gets state 'A' (<State('D')@140486642630440>) 
<State('D')@140329230661784> 
>>> m.get_state('A').name # Gets state name 'A' ('D') 
'D' 
>>> # The following generates an error, since the state isn't renamed in the machine 
>>> m.get_state('D') # (ValueError: State 'D' is not a registered state.) 
ValueError: State 'D' is not a registered state. 

这不工作,我只是重新命名的名称字符串,而不是实际的状态。 我想要的结果是('A')改为('D')到国家的所有引用,因此,例如机器m的过渡将是[['ab','D','B'],['bc','B','C'],['ca','C','D']]

这是可能的,还是我要坚持添加/删除的状态和所有它是单独的转换引用?如果是这种情况,那么可行的方法是什么?

回答

0

简短的回答:这不是那么容易。最稳定的方式将是您动态适应的外部名称映射。

names = {"A": "stateA", "B": "stateB"} 
names["A"] = "stateC" 

这也可以在State.name保留给机器逻辑和State.system_name可以不害改变的State一个子类来完成。

如果你想/需要实际更换的状态名称。请继续阅读。

较长的回答:转换管理状态在OrderedDict其中键代表状态名称。另外,转换被收集到列表字典中的事件中,同样以源状态名称作为关键字。这些事件被绑定到模型上,作为一种类似于过渡触发器的方法。该转换本身包含的属性sourcedest包含他们的起点和终点的..等待...状态名称。 如果启用了自动转换功能,我们还有to_<state.name>功能被分配给模型。与模型有更多的州名相关纠缠,包括on_enter/exit_<state.name>。这意味着有很多地方需要更换字符串。

凡有意愿,有办法。 - 某些Python编码器

您可以深入挖掘并重命名与状态相关的所有内容,但这会有一些注意事项。最明显的一点是:如果你的Model类定义了一个on_enter_A,你不能在你的实例中重命名该方法。在状态实例初始化期间,它已被添加到状态。您可以过滤来自State.on_enter/exit属性的方法或让它们分配。这也意味着,如果将状态从“A”重命名为“B”,即使模型中存在on_enter_B方法,也不会重新分配回调。

from transitions import Machine 
from collections import OrderedDict 


def rename_state(machine, old, new): 
    # rename transitions 
    for trigger, event in machine.events.items(): 
     if old in event.transitions: 
      trs = event.transitions.pop(old) 
      for tr in trs: 
       tr.source = new 
      event.transitions[new] = trs 
     for trs in event.transitions.values(): 
      for tr in trs: 
       if tr.dest == old: 
        tr.dest = new 

    if "to_{0}".format(old) in machine.events: 
     ev = machine.events.pop("to_{0}".format(old)) 
     machine.events["to_{0}".format(new)] = ev 
    # rename model properties 
    for mo in machine.models: 
     func = getattr(mo, 'to_' + old, False) 
     if func: 
      setattr(mo, 'to_' + new, func) 
      delattr(mo, 'to_' + old) 
     if mo.state == old: 
      mo.state = new 
    # rename state and reconstruct ordered dict for states 
    machine.states[old].name = new 
    machine.states = OrderedDict((new if k == old else k, v) for k, v in machine.states.viewitems()) 


class Model: 

    def on_exit_A(self): 
     print("Exited A!") 

    def on_exit_B(self): 
     print("Exited B") 

model = Model() 
m = Machine(model, initial='A') 
m.add_state("A") 
m.add_state("C") 
m.add_transition('go', 'A', 'C') 
rename_state(m, "A", "B") 
print model.state # >>> B 
model.go() # >>> Exited A! 
print model.state # >>> C 
print m.get_state('B') 

是否有(更好)替代品?

您可以删除机器上的转换,但是如果您计划删除并重新添加状态和转换,必须严格筛选状态。

你也可以有一个你保留在某处的转换和状态列表。如果您需要重命名状态,则需要更改列表并创建一个新机器:

from transitions import Machine 

states = ["A", "B"] 
transitions = [['ab', 'A', 'B'], ['ba', 'B', 'A']] 


class Model(): 
    pass 

model = Model() 

m = Machine(model, states=states, transitions=transitions, initial='A') 
model.ab() 
print model.state # >>> B 

# rename states and transitions 
states = [s if s != "A" else "C" for s in states] 
transitions = [[t, s if s != "A" else "C", d if d != "A" else "C"] for t, s, d in transitions] 

m = Machine(model, states=states, transitions=transitions, initial=model.state) 
model.ba() 
print model.state # >>> C 

但这也包含风险。如前所述,机器将某些功能分配给模型。如果无法重新初始化模型,至少会有一些分配给模型的自动转换失效。尝试在第二个示例中调用model.to_A()以查看我的意思。

相关问题