我使用Transitions,这是一个非常有用的用于python的FSM工具。我想让这些状态变得更加呃有状态......这样变量对于状态就可以是局部的,并且当状态进入或离开时它们的值会改变。我在机器中得到了相当数量的实例变量 - 我真的很想在状态中使用其中的一些值(例如,我一直处于这种状态多长时间)。它们不是模型的属性,它们是通过状态进展的属性。在转换中制作“状态”fsm package更“有状态”
我不知道是否有'最好的办法'来做到这一点?子类状态?
感谢
我使用Transitions,这是一个非常有用的用于python的FSM工具。我想让这些状态变得更加呃有状态......这样变量对于状态就可以是局部的,并且当状态进入或离开时它们的值会改变。我在机器中得到了相当数量的实例变量 - 我真的很想在状态中使用其中的一些值(例如,我一直处于这种状态多长时间)。它们不是模型的属性,它们是通过状态进展的属性。在转换中制作“状态”fsm package更“有状态”
我不知道是否有'最好的办法'来做到这一点?子类状态?
感谢
我不知道的“最佳途径”,但一个合理的方法取决于你想要达到的目标。你可以a)子类状态,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
。
这不是状态局部变量的通常解释。你提出的是持久性的变量:当你进入一个状态时,它仍然和上次一样具有相同的变量。通常情况下,你需要将变量放入一个状态,以确保每次进入状态时都会对它们进行新的初始化,而这种解决方案**不会。我不确定这是OP的想法,但我认为我应该评论,因为这个建议让我完全错过了错误的胡同。 –
@DanHule:好评。在转换中,状态实例是持久的。 OP声明“...,当状态进入或离开时,它们的值改变了**。”(这可能是错误地)暗示我不认为这些属性是范围/时间属性。对于* local/temporal/scoped *状态[this](https://github.com/aleneum/rsbhsm/blob/master/rsbhsm/rsbhsm.py#L99)可能会有所帮助。每次输入状态时,都可以传递一个类或类路径,用于初始化对象。 – aleneum