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

How to add tags to an existing state object in Pytransitions?

在分配给我的项目中,我们使用 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"]) 或以任何其他方式考虑我的遗留设置。我该怎么做?

我的第一个建议是检查是否可以通过使用专用的 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...

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