transitions propose des transitions ordonnées ainsi que des transitions queued
qui pourraient être ce que vous recherchez. L'astuce consiste à appeler le même événement à chaque fois que le même événement a été traité (avec finalize
). Les rappels passés à finalize
seront traités même si la transition n'a pas abouti (tous les conditions
ne sont pas retournés True
). Avec queued
, les transitions ne traiteront pas l'événement immédiatement, mais juste après l'événement actuellement traité, ce qui empêchera une récursion massive.
from transitions import Machine
import time
class Model(object):
# initialise counter and counter limit
def __init__(self):
self.counter = 0
self.limit = 5
# will be called in every cycle and increase the counter
def increase_counter(self):
self.counter += 1
print("Counter increased to ", self.counter)
time.sleep(0.5)
# will be called whenever a new state has been entered
def reset_counter(self):
self.counter = 0
print("Counter reset; Current state is ", model.state)
# this function returns whether the limit has already been reached
def limit_reached(self):
return self.counter >= self.limit
# initialising the previously defined model
model = Model()
# creating some state names
states = ['A', 'B', 'C', 'D']
# configuring the state machine:
# pass the model (for callbacks), pass the state names,
# disable auto_transitions since we will not need them
# set the initial state to 'A' and call a (currently) undefined
# model function 'next_state' after EVERY triggered event.
# 'queued' means that every transition is finished before the next event is handled
machine = Machine(model, states=states, auto_transitions=False,
queued=True, initial='A', finalize_event='next_state')
# now add ordered transitions:
# Depending on the order of the passed state names,
# create transitions from each state 'n' to state 'n+1' called 'next_state'.
# 'prepare' each transition attempt by increasing the counter
# afterwards check the 'conditions' (is the counter limit reached)
# if all callbacks in 'conditions' return True, the transition
# is conducted and callbacks in 'after' are processed (counter reset)
machine.add_ordered_transitions(prepare='increase_counter', conditions='limit_reached',
after='reset_counter', trigger='next_state')
# model will go into an infinite loop; can be triggered in a thread
model.next_state()
Vous pouvez essayer de réduire la minuterie de sommeil dans increase_counter
pour vérifier si vous appuyez sur une erreur de récursion (vous ne devriez pas). Si vous définissez queued=False
, ce qui correspond au comportement standard, vous obtiendrez plus ou moins directement l'erreur de récurrence puisque tous les déclencheurs de la machine seront traités instantanément.
Je regarderais probablement les coroutines pour cela –
@ user252046 quel est le problème avec récursive. pourquoi voulez-vous "sans"? – Rajez
Je ne veux pas que le programme rappelle après avoir atteint le cas de base. Et la boucle continue pour toujours. Je sais que cela peut être accompli en ayant une boucle principale qui fait appel aux fonctions, mais cela créerait beaucoup de désordre. – user252046