python - 如何在 Pytransitions 中向现有状态对象添加标签?

标签 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("初始", on_exit="some_callback", tag=["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)

但是您的问题是关于如何在创建状态之后注入(inject)标签功能。可能是因为它需要重大重构和深入挖掘来改变状态创建。添加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...

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

关于python - 如何在 Pytransitions 中向现有状态对象添加标签?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57868795/

相关文章:

Python:进程运行的时间

python - PySpark - 带有 lambda 函数的映射

python - socket.gaierror : [Error -2] Name or service not known

python - spyder IDE 的 ipython 启动配置

javascript - jquery按钮值改变效果

iphone - 更改 UIView 动画转换背后的背景

jquery - <li> 的页面转换不起作用

c# - 无状态状态机框架和高 CPU 使用率

state-machine - 工作流引擎的用例