(simplifié d'une question trop bavard je posté plus tôt!)générer dynamiquement une fonction de générateur d'un blob de texte
d'une chaîne Python contenant du code Python valide qui contient une déclaration « rendement », comment puis-je construire un générateur que exec est cette chaîne?
Par exemple, compte tenu de la chaîne:
code_string = """for x in range(0, 10):
yield x
"""
Je veux construire un générateur f qui exécute code_string tel que (dans cet exemple particulier):
assert(list(f()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Notez que code_string est arbitraire, donc cette assertion est uniquement valable pour l'exemple ci-dessus. code_string peut contenir n'importe quel code python valide contenant une instruction yield.
Merci!
Edit:
La première solution que je pensais était juste munge "def f():" dans la chaîne et en retrait chaque ligne par programmation. Cependant, cela échoue si code_string utilise une indentation différente. J'espérais qu'il y avait quelques functools kung-fu peu connus qui peuvent construire une fonction à partir d'une goutte de texte.
Edit2:
J'ai essayé aussi un exec dans une fonction comme ceci:
code = "for x in range(0, 10): yield x"
def f():
exec code in globals(), locals()
Cela se traduit par "SyntaxError: 'rendement' en dehors de la fonction"
Résolu: Problème Je suis corrigé, l'indentation est relative, de sorte que cela fonctionne:
code_string = """for x in range(0, 10):
yield x
"""
exec "def f():\n" + [(" " + line) for line in code_string.split('\n')]) + "\n"
assert list(f()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Croyez-moi, ce n'est pas la partie du problème que vous voulez résoudre. –
:-) J'apprécie le conseil, mais j'aime résoudre les problèmes. –
J'ai supprimé ma réponse, car je ne sais pas comment la faire fonctionner (je pense que le exec() n'était appelé que lorsque la fonction produite par la fermeture était appelée, au lieu de l'appel de la fonction de production). Je suggérerais de trouver un autre moyen de résoudre ce problème, comme l'a suggéré Ignacio. – Wilduck