问题描述
我正在尝试将参数传递给条件。但是它给出了以下错误
代码:
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'
,并且过渡肯定会发生。因此,before
在self.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)
可以很容易地“丢弃”不需要的参数。我也建议始终将参数作为关键字参数传递,即使也支持位置参数。以我的经验,这使代码更易于理解(例如,更易于阅读方法定义),并减少了错误源(例如,错误的参数映射)。