在转换中,如何通过函数引用而不是函数名字符串来定义回调函数

时间:2016-10-12 06:15:00

标签: python transitions

在转换中,回调定义如下:

State(name='solid', on_exit=['say_goodbye'])
machine.add_transition('melt', 'solid', 'liquid', before='set_environment')

我想使用另一个类

中定义的回调函数
class MyClass(object):
    def func(self):
        print('nothing')
class NarcolepticSuperhero(object):

    # Define some states. Most of the time, narcoleptic superheroes are just like
    # everyone else. Except for...
    states = [State('asleep'), 'hanging out', 'hungry', 'sweaty', 'saving the world']

    def __init__(self, name):

        # No anonymous superheroes on my watch! Every narcoleptic superhero gets
        # a name. Any name at all. SleepyMan. SlumberGirl. You get the idea.
        self.name = name
        self.mc = MyClass()
        # Initialize the state machine
        self.machine = Machine(model=self, states=NarcolepticSuperhero.states, initial='asleep')
        self.machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out', prepare=self.mc.func)

m = NarcolepticSuperhero('Superman')
m.wake_up()

得到TypeError: getattr(): attribute name must be string

我的完整代码是这样的。我有几个Mission,每个任务有不同的方法。你知道一个英雄不能用同样的动作来击败不同的怪物。

英雄不能总是击败怪物。因此,根据prepare,我们会选择retreatbeat_the_next

class Mission(object):
    def __init__(self, name):
        super().__init__()
        self.result = 0
        self._state = State(name=name, on_exit=self.on_exit, on_enter=self.on_enter)
        self.state = name
    def fire(self):
        print('checking state {}'.format(self.name))
        self.result = random.random()
    def on_enter(self):
        print('enter state {}'.format(self.name))
    def on_exit(self):
        print('checking state {}'.format(self.name))
    def condition1(self):
        return self.result > 0.6
    def condition2(self):
        return self.result > 0.3
    def condition3(self):
        return self.result > 0.1

class Robot(object):
    def __init__(self):
        super().__init__()
        self.a = Mission('a')
        self.b = Mission('b')
        self.c = Mission('c')
        self.states = [i._state for i in [self.a, self.b, self.c]]
        self.machine = Machine(model=self, states=self.states, initial=self.a.state, auto_transitions=False)
        self.machine.add_transition( trigger='go_out', source=self.a.state, dest=self.b.state , prepare = self.a.fire, conditions = [self.a.condition2], after = 'beat_next')
        self.machine.add_transition( trigger='go_back', source=self.a.state, dest=self.c.state , after = 'sleep')
        self.machine.add_transition( trigger='beat_next', source=self.b.state, dest=self.c.state , after = 'sleep')
        self.machine.add_transition( trigger='sleep', source=self.c.state, dest=self.a.state )

    def show_graph(self):
        self.graph.draw('state.png', prog='dot')
        display(Image('state.png'))

机器型号为self,因此我无法将其更改为mc

1 个答案:

答案 0 :(得分:0)

一种可能的方法是将您的计算机绑定到NarcolepticSuperhero实例,而不是绑定到接口。

class StateMachineInterface(object):
    superhero = None

    def __init__(self, superhero):
        self.superhero = superhero

    def start(self):
        """Initiate State Machine with all states and transitions"""
        machine = Machine(
            self,
            states=STATES,
            initial=INITIAL_STATE,
        )
        machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out', prepare='wakeup_prepare_callback')

        return machine

    def wakeup_prepare_callback(self):
        return self.superhero.func()


# Usage:

m = NarcolepticSuperhero('Superman')
machine = StateMachineInterface(m)
machine.start()
machine.wake_up()

documentation

中建议了这一原则