如何在Pytransitions中将标签添加到现有状态对象?

时间:2019-09-10 10:24:46

标签: python transition state-machine

在分配给我的项目中,我们使用pytransitions。我们创建了状态,并配备了其他属性,并首先将其作为对象逐个添加到列表中。然后,此State对象列表将传递到Machine对象。 这是一个简单的示例:

from transitions import State

states = []
state_initial = State("initial", on_exit="some_callback")
text = "this is some text"
state.text = text
states.append(state)

这是机器的创建方式:

from transitions import Machine
from some_library import SomeClass
from my_module import user_transitions

class User:
    states = states
    initial_state = states[0]
    def __init__(self, some_param: str, another_param: SomeClass = default_param):
        self.machine = Machine(model=self,
                               states=User.states,
                               initial=User.initial_state,
                               transitions=user_transitions,
                               prepare_event="preparing_callback",
                               after_state_change="ending_callback")

我想做的是在创建状态对象时或之后将标签添加到状态中。我的意思是transitions.extensions.states中的标签,因此我可以使用is_tag这样的方法(如文档中的方法)来获取它们。像state_initial.add_tags(["tag1", "tag2"])state_initial = State("initial", on_exit="some_callback", tags=["tag1", "tag2"]) 或以其他任何方式考虑我的旧设置。我该怎么办?

1 个答案:

答案 0 :(得分:1)

我的第一个建议是检查是否可以通过使用专用的TextState而不是仅仅分配其他属性来简化状态创建过程。这样,您可以使状态配置更容易理解。从yaml或json文件中读取机器配置也变得更加容易。

from transitions import Machine, State
from transitions.extensions.states import Tags

# option a) create a custom state class and use it by default
# class TextState and CustomState could be combined of course
# splitting CustomState into two classes decouples tags from the 
# original state creation code
class TextState(State):

    def __init__(self, *args, **kwargs):
        self.text = kwargs.pop('text', '')
        super(TextState, self).__init__(*args, **kwargs)

class CustomState(Tags, TextState):
    pass


class CustomMachine(Machine):
    state_cls = CustomState


states = []
state_initial = CustomState("initial", text="this is some text")
# we can pass tags for initialization
state_foo = dict(name="foo", text="bar!", tags=['success'])
states.append(state_initial)
states.append(state_foo)

# [...] CustomMachine(model=self, states=User.states, initial=User.initial_state)

但是您的问题是关于如何创建标记功能 AFTER 状态。可能是因为它需要进行重大的重构和深入挖掘才能改变状态的创建。添加state.tags = ['your', 'tags', 'here']很好,应该可以立即创建图形和标记。要使state.is_<tag>正常运行,您可以更改其__class__属性:

from transitions import Machine, State
from transitions.extensions.states import Tags

# option b) patch __class__
states = []
state_initial = State("initial")
state_initial.text = "this is some text"
# we can pass tags for initialization
state_foo = State("foo")
state_foo.text = "bar!"
state_foo.tags = ['success']
states.append(state_initial)
states.append(state_foo)

# patch all states
for s in states:
    s.__class__ = Tags
    s.tags = []

# add tag to state_foo
states[1].tags.append('success')

class User:

    states = states
    initial_state = states[0]

    def __init__(self):
        self.machine = Machine(model=self,
                               states=User.states,
                               initial=User.initial_state)

user = User()
user.to_foo()
assert user.machine.get_state(user.state).is_success  # works!
assert not user.machine.get_state(user.state).is_superhero  # bummer...

但是,根据我的经验,当您尝试将机器配置与其余代码库区分开时,代码变得更加易于理解和重用。下一个使用您的代码的人可能会忽略在代码中的某个位置修补状态并分配自定义参数,当状态在两个调试断点之间更改其类时,这肯定令人惊讶。