Récemment, j'ai écrit une fonction pour générer certaines séquences avec des contraintes non triviales. Le problème était accompagné d'une solution récursive naturelle. Or il se trouve que, même pour une entrée relativement petite, les séquences sont plusieurs milliers, donc je préférerais utiliser mon algorithme comme générateur plutôt que de l'utiliser pour remplir une liste avec toutes les séquences.
Voici un exemple. Supposons que nous voulions calculer toutes les permutations d'une chaîne de caractères avec une fonction récursive. L'algorithme naïf suivant prend un argument supplémentaire "stockage" et ajoute une permutation à celui-ci chaque fois qu'il en trouve une :
def getPermutations(string, storage, prefix=""):
if len(string) == 1:
storage.append(prefix + string) # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], storage, prefix+string[i])
storage = []
getPermutations("abcd", storage)
for permutation in storage: print permutation
(Ne vous souciez pas de l'inefficacité, ce n'est qu'un exemple).
Je veux maintenant transformer ma fonction en générateur, c'est-à-dire produire une permutation au lieu de l'ajouter à la liste de stockage :
def getPermutations(string, prefix=""):
if len(string) == 1:
yield prefix + string # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], prefix+string[i])
for permutation in getPermutations("abcd"):
print permutation
Ce code ne no fonctionnent (la fonction se comporte comme un générateur vide).
Est-ce que j'ai manqué quelque chose ? Y a-t-il un moyen de transformer l'algorithme récursif ci-dessus en un générateur sans la remplacer par une méthode itérative ?