我正在使用Transitions,这是一个非常有用的python FSM工具。我想使状态更多,嗯,有状态......这样变量可以是状态的局部变量,并且当输入或离开状态时它们的值会改变。我最终在机器中有相当数量的实例变量 - 我真的想要一些状态中的值(例如,我在这个状态下有多长时间)。它们不是模型的属性,它们是通过状态进展的属性。
我想知道是否有“最好的方法”来做到这一点?子类状态?
感谢
答案 0 :(得分:1)
我不知道最好的方式'但合理的方法取决于你想要达到的目标。您可以a)子类State,b)修饰初始化状态或c)手动初始化(子类化)状态并将它们传递给机器。
A)如果每个州都有相同的属性,您可以按照建议将子类化为子类:
import transitions.extensions.nesting as nesting
class CounterState(nesting.NestedState):
def __init__(self, *args, **kwargs):
super(CounterState, self).__init__(*args, **kwargs)
self.entered = self.exited = 0
def enter(self, event_data):
self.entered += 1
def exit(self, event_data):
self.exited += 1
def __str__(self):
return "State {0} has been entered {1} times and exited {2} times".format(self.name, self.entered, self.exited)
class CounterMachine(nesting.HierarchicalMachine):
@staticmethod
def _create_state(*args, **kwargs):
return CounterState(*args, **kwargs)
machine = CounterMachine(states=['A', 'B'], initial='A')
a = machine.get_state('A')
b = machine.get_state('B')
print(a) # >>> State A has been entered 0 times and exited 0 times
machine.to_B()
print(a) # >>> State A has been entered 0 times and exited 1 times
print(b) # >>> State B has been entered 1 times and exited 0 times
我在这里使用了NestedMachine
,因为到目前为止_create_state
中没有Machine
。 更新:从版本0.4.4
开始,它也适用于Machine
。
B)另一种方法是通过模型对启动的状态对象进行一些装饰:
from transitions import Machine
class Model(object):
def __init__(self):
self.machine = Machine(model=self, states=['A', 'B'], initial='A',
before_state_change='exit_state',
after_state_change='enter_state')
# loop through all the states and attach attributes
for state in self.machine.states.values():
state.entered = 0
state.exited = 0
def enter_state(self):
# retrieve the state object by name
self.machine.get_state(self.state).entered += 1
def exit_state(self):
self.machine.get_state(self.state).exited += 1
def print_state(state):
print("State {0} has been entered {1} times and exited {2} times".format(state.name, state.entered, state.exited))
m = Model()
a = m.machine.get_state('A')
b = m.machine.get_state('B')
print_state(a)
m.to_B()
print_state(a)
print_state(b)
C)如果必须单独处理每个州,您可以手动启动状态并将实例传递给机器而不是名称:
from transitions import Machine, State
class TicketState(State):
def __init__(self, name, tickets):
super(TicketState, self).__init__(name)
self.tickets = tickets
class Model(object):
def __init__(self):
# Using our own state
a = TicketState('A', 10)
# Setting tickets ourselves
b = State('B')
b.tickets = 3
self.machine = Machine(self, states=[a, b], initial='A',
before_state_change='decrease_tickets')
def tickets_left(self):
return self.machine.get_state(self.state).tickets > 0
def decrease_tickets(self):
s = self.machine.get_state(self.state)
s.tickets -= 1
if s.tickets < 0:
raise Exception('No Tickets left!')
print("State {0} has {1} tickets left.".format(s.name, s.tickets))
m = Model()
m.to_B() # >>> State A has 9 tickets left.
m.to_A() # >>> State B has 2 tickets left.
当然,属性和名称的数量可能有所不同。您也可以将before_state_change
回调传递给on_enter/exit
对象,以便在转换期间单独处理每个状态,而不是使用机器回调State
。或者,如果您只需要一组不同的州类型,例如State.enter(self, event_data)
和/或TimedState
,则为子类CounterState
。