は、私が「最良の方法」を認識していないですが、合理的なアプローチは、あなたが達成したいかに依存します。 a)状態のサブクラス化、b)初期化された状態の修飾、またはc)手動での初期化(サブクラス化)された状態を機械に渡すことができます。すべての状態は同じ属性を持っている場合は、あなたが示唆したよう
A)あなたは状態をサブクラス化することができます_create_state
は、これまでMachine
では利用できないので、私はここにNestedMachine
を使用していた
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
。 更新:バージョン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
オブジェクトに渡して、遷移中に各状態を個別に処理することもできます。またはTimedState
やCounterState
のような異なる状態タイプのセットが必要な場合は、State.enter(self, event_data)
をサブクラス化してください。
これは、状態ローカル変数の通常の解釈ではありません。あなたが提案しているのは、永続的な変数です。状態を入力すると、前回と同じ変数が残っています。通常は、変数を状態に入れて、状態が入力されるたびに変数が新しく初期化されるようにします。これは**この方法ではできません**。私はそれがOPが望んでいたかどうか分からないが、この提案が私に間違った路地を完全に導いたので、私はコメントしなければならないと思った。 –
@DanHule:良い発言。トランジションでは、状態インスタンスは永続的です。 OPは "...、状態が入力されたとき、またはその値が**変化した。**"ということは、スコープ/時間属性ではないことを(私が誤って)暗示している可能性があります。 * local/temporal/scoped *州については、[this](https://github.com/aleneum/rsbhsm/blob/master/rsbhsm/rsbhsm.py#L99)が参考になるかもしれません。状態が入力されるたびに、オブジェクトを初期化するために使用されるクラスまたはクラスパスを渡すことができます。 – aleneum