如何在pytransition中的条件函数中传递事件参数 如何将变量传递给回调

问题描述

我正在尝试将参数传递给条件。但是它给出了以下错误

代码:

from transitions import Machine

class evenodd(object):
    def get_no(self,event):
        self.no = event.kwargs.get('no',0)
    def calc_mod(self,event):
        self.mod = event.kwargs.get('mod',self.no%2)
    
    def is_even(self,event):
        if self.mod == 0:
            return True
        
obj = evenodd()
machine = Machine(obj,['init','getno','even','odd'],send_event=True,initial='init',ignore_invalid_triggers=True,auto_transitions=False)
machine.add_transition('enterno','init',before='get_no')
machine.add_transition('isevenodd',before='calc_mod',conditions=['is_even'])
machine.add_transition('isevenodd','odd',conditions=['is_odd']) 


s_state = obj.state
print("state --> "+s_state)
trigger = machine.get_triggers(s_state)[0]
print("transition --> "+trigger)
obj.enterno(2)
s_state = obj.state
print("state --> "+s_state)
trigger = machine.get_triggers(s_state)[0]
print("transition --> "+trigger)
obj.isevenodd()
s_state = obj.state
print("state --> "+s_state)

错误:

state --> init
transition --> enterno
state --> getno
transition --> isevenodd
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-75-d8ede3775dc5> in <module>
      8 trigger = machine.get_triggers(s_state)[0]
      9 print("transition --> "+trigger)
---> 10 obj.isevenodd()
     11 s_state = obj.state
     12 print("state --> "+s_state)

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in trigger(self,model,*args,**kwargs)
    388         # Machine._process should not be called somewhere else. That's why it should not be exposed
    389         # to Machine users.
--> 390         return self.machine._process(func)
    391 
    392     def _trigger(self,**kwargs):

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in _process(self,trigger)
   1112             if not self._transition_queue:
   1113                 # if trigger raises an Error,it has to be handled by the Machine.process caller
-> 1114                 return trigger()
   1115             else:
   1116                 raise MachineError("Attempt to process events synchronously while transition queue is not empty!")

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in _trigger(self,**kwargs)
    406                 raise MachineError(msg)
    407         event_data = EventData(state,self,self.machine,args=args,kwargs=kwargs)
--> 408         return self._process(event_data)
    409 
    410     def _process(self,event_data):

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in _process(self,event_data)
    415             for trans in self.transitions[event_data.state.name]:
    416                 event_data.transition = trans
--> 417                 if trans.execute(event_data):
    418                     event_data.result = True
    419                     break

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in execute(self,event_data)
    260         _LOGGER.debug("%sExecuted callbacks before conditions.",event_data.machine.name)
    261 
--> 262         if not self._eval_conditions(event_data):
    263             return False
    264 

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in _eval_conditions(self,event_data)
    241     def _eval_conditions(self,event_data):
    242         for cond in self.conditions:
--> 243             if not cond.check(event_data):
    244                 _LOGGER.debug("%sTransition condition failed: %s() does not return %s. Transition halted.",245                               event_data.machine.name,cond.func,cond.target)

~\Anaconda3\envs\ml_nlp_cpu\lib\site-packages\transitions\core.py in check(self,event_data)
    179         predicate = event_data.machine.resolve_callable(self.func,event_data)
    180         if event_data.machine.send_event:
--> 181             return predicate(event_data) == self.target
    182         return predicate(*event_data.args,**event_data.kwargs) == self.target
    183 

<ipython-input-74-5dc86072aabd> in is_even(self,event)
      7     def is_even(self,event):
      8         """ Basically a coin toss. """
----> 9         if self.mod == 0:
     10             return True
     11 

AttributeError: 'evenodd' object has no attribute 'mod'

如何在每个回调中共享变量no和mod。我试图使用该事件。 在这个简单的示例中,我尝试根据给定输入是偶数还是奇数来创建状态机,以达到状态。

解决方法

您可以共享变量作为模型的属性。但是,您需要考虑回调执行顺序。根据{{​​1}} documentation,回调按以下顺序执行:

  • transitions
  • 'machine.prepare_event'
  • 'transition.prepare'
  • 'transition.conditions'
  • 'transition.unless'
  • 'machine.before_state_change'
  • 'transition.before'
  • 'state.on_exit'
  • <STATE CHANGE>
  • 'state.on_enter'
  • 'transition.after'
  • 'machine.after_state_change'

您可以看到,在评估条件后 触发了'machine.finalize_event',并且过渡肯定会发生。因此,beforeself.mod中不可用,因为尚未调用is_even。该列表还显示了如何处理此问题:在calc_mod中执行calc_mod而不是prepare

before

machine.add_transition('isevenodd','getno','even',prepare='calc_mod',conditions=['is_even']) machine.add_transition('isevenodd','odd',conditions=['is_odd']) 正是针对需要条件设置的用例而引入的。如果还需要“拆下”,则可以使用prepare,无论是否进行转换,始终会调用它。谈到回调解析顺序:您可以将条件检查传递给machine.finalize_event,如果条件检查结果为true,则该检查将暂停过渡。您可以将unless替换为conditions='is_odd'

如果您不介意一些隐式逻辑,则可以完全放弃“ is_odd”检查。始终按添加顺序评估一组有效触发器。这意味着unless='is_even'仅在发现'getno' -> 'odd'无效时才被考虑。在设计方面,添加了 last 的无条件过渡将充当“ else”子句,当无法满足先前的一组条件时将执行该子句。

如何将变量传递给回调

一种方法是处理'getno' -> 'even'对象,该对象在计算机上event时传递给回调。您还可以将变量作为触发参数传递:

send_event=True

如果这样做,则必须确保每个回调都可以使用所有参数。使用from transitions import Machine class evenodd(object): def get_no(self,no=0,**kwargs): self.no = no def calc_mod(self,mod=None,**kwargs): self.mod = mod if mod else self.no % 2 def is_even(self): return self.mod == 0 obj = evenodd() machine = Machine(obj,['init','odd'],initial='init',ignore_invalid_triggers=True,auto_transitions=False) machine.add_transition('enterno','init',before='get_no') machine.add_transition('isevenodd',conditions=['is_odd']) obj.enterno(no=2) obj.isevenodd() print("state --> " + obj.state) 可以很容易地“丢弃”不需要的参数。我也建议始终将参数作为关键字参数传递,即使也支持位置参数。以我的经验,这使代码更易于理解(例如,更易于阅读方法定义),并减少了错误源(例如,错误的参数映射)。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...