2017-08-25 2 views
-3

J'essaie de passer d'un état à un autre. Chaque état est représenté par une fonction. Je voudrais gérer la logique de commutation à l'intérieur de la fonction au lieu d'une boucle principale qui appelle la fonction. Y at-il une bibliothèque python qui permet ce genre de modèle. Ainsi, par exemple:Y at-il une librairie python qui vous permet d'appeler une fonction dans une fonction sans créer de pile récursive?

def c(count): 
    if count<10: 
     a(count+1) 
     print("dont' keep track of post-order printing") 
    else: 
     print("when count is reached, program should terminate") 
def b(count): 
    c(count): 
def a(count): 
    b(count) 
a() 

Ceci est juste un exemple, je suis en train d'utiliser un modèle d'états finis où la logique est à l'intérieur de la transition on_enter méthodes. Fondamentalement, la machine passera automatiquement d'un état à l'autre, sans l'utilisation d'une boucle principale.

+0

Je regarderais probablement les coroutines pour cela –

+0

@ user252046 quel est le problème avec récursive. pourquoi voulez-vous "sans"? – Rajez

+0

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

Répondre

0

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.

+0

Cela fonctionne parfaitement! – user252046

0

J'espère qu'il peut, il peut convient à vos attentes

def c(count): 
    if count<10: 
     print("don't keep track of post-order printing") 
     c(count+1) 
    else: 
     print("when count is reached, program should terminate") 

Sortie:

>>> c(1) 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
don't keep track of post-order printing 
when count is reached, program should terminate