首页 > 解决方案 > 如何将参数传递给`transitions`库中的on_enter回调?

问题描述

我想使用transitions,并且需要一个我在文档中找不到的相当微不足道的功能,并且想知道它是否已实现:

我想on_enter在某个状态上定义一个回调,但将一个参数传递给该回调。至少要知道我是从哪个州进入的。

从文档:

class Matter(object):
    def say_hello(self): print("hello, new state!")
    def say_goodbye(self): print("goodbye, old state!")

lump = Matter()

# Same states as above, but now we give StateA an exit callback
states = [
    State(name='solid', on_exit=['say_goodbye']),
    'liquid',
    { 'name': 'gas', 'on_exit': ['say_goodbye']}
    ]

machine = Machine(lump, states=states)
machine.add_transition('sublimate', 'solid', 'gas')

# Callbacks can also be added after initialization using
# the dynamically added on_enter_ and on_exit_ methods.
# Note that the initial call to add the callback is made
# on the Machine and not on the model.
machine.on_enter_gas('say_hello')

# Test out the callbacks...
machine.set_state('solid')
lump.sublimate()
>>> 'goodbye, old state!'
>>> 'hello, new state!'

我缺乏的是

def say_hello(self, param): print(f"hello, new state! here is your param: {param}")

这可以以某种方式很好地完成吗?

一个明显不好的解决方案是保留一个self._last_state论点并自己坚持下去。
我正在寻找内置的东西。

标签: pythontransitionstate-machinefsmpytransitions

解决方案


transitions' 文档的部分称为传递数据

...您可以将任何位置或关键字参数直接传递给触发器方法(在调用 add_transition() 时创建)[...] 您可以将任意数量的参数传递给触发器。这种方法有一个重要限制:状态转换触发的每个回调函数都必须能够处理所有参数。

对于您的特定示例,这可能如下所示:

from transitions import Machine

class Matter(object):
    def say_hello(self, param):
        print(f"hello, new state! Here is your param: {param}")

    # Every callback MUST be able to process possible callback parameters
    # If parameters are not needed, just use *args and **kwargs in the definition
    def say_goodbye(self, *args):
        print("goodbye, old state!")


lump = Matter()
machine = Machine(lump, states=[{'name': 'solid', 'on_exit': 'say_goodbye'},
                                'liquid',
                                {'name': 'gas', 'on_enter': 'say_hello'}],
                  transitions=[['sublimate', 'solid', 'gas']], initial='solid')

# pass param as arg
lump.sublimate(lump.state)
# or as kwarg
# lump.sublimate(param=lump.state)

还有第二种方法是通过传入构造函数来传递send_event=True数据Machine。这将改变transitions将触发参数传递给回调的方式:

如果您在机器初始化时设置 send_event=True,则触发器的所有参数都将包装在 EventData 实例中并传递给每个回调。(EventData 对象还维护与事件关联的源状态、模型、转换、机器和触发器的内部引用,以防您需要访问这些以进行任何操作。)

这可能更适合您的用例,因为EventData对象还包含有关已执行转换的信息,其中包含源状态的名称:

from transitions import Machine, EventData

class Matter(object):
    def say_hello(self, event: EventData):
        print(f"hello, new state! Here is your param: {event.kwargs['param']}. "
              f"I came here from state '{event.transition.source}'.")

    def say_goodbye(self, event):
        print("goodbye, old state!")


lump = Matter()
machine = Machine(lump, states=[{'name': 'solid', 'on_exit': 'say_goodbye'},
                                'liquid',
                                {'name': 'gas', 'on_enter': 'say_hello'}],
                  transitions=[['sublimate', 'solid', 'gas']], initial='solid', send_event=True)

lump.sublimate(param=42)

推荐阅读