如何将参数传递给 `transitions` 库中的 on_enter 回调?

How to pass parameters to on_enter callbacks in `transitions` library?

我想使用 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 论点并由我自己维护。
我正在寻找内置的东西。

transitions' 文档中名为 Passing Data 的部分:

... you can pass any positional or keyword arguments directly to the trigger methods (created when you call add_transition()) [...] You can pass any number of arguments you like to the trigger. There is one important limitation to this approach: every callback function triggered by the state transition must be able to handle all of the arguments.

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

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)

还有第二种方式传递数据,在Machine构造函数中传递send_event=True。这将改变 transitions 将触发器参数传递给回调的方式:

If you set send_event=True at Machine initialization, all arguments to the triggers will be wrapped in an EventData instance and passed on to every callback. (The EventData object also maintains internal references to the source state, model, transition, machine, and trigger associated with the event, in case you need to access these for anything.)

这可能更适合您的用例,因为 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)