7
votes

Stop Generator de l'intérieur du bloc de Python

J'ai un générateur qui donne des nœuds d'un graphique acyclique dirigé (DAG), de profondeur d'abord: xxx

je peux itération sur les nœuds comme celui-ci xxx < / Pré>

Je voudrais pouvoir dire au générateur, de la boucle de la boucle, d'arrêter d'aller plus loin dans le graphique si une condition est remplie.

Je suis venu avec la solution suivante qui utilise une fonction externe. xxx

Cette solution me force à déclarer des variables dont j'ai besoin avant que Stop_Crit soit défini alors ils peuvent être consultés de celui-ci.

dans Ruby, le rendement renvoie la dernière expression du bloc de sorte que cela puisse être utilisé de manière commodément pour dire au générateur de continuer ou de s'arrêter.

Quel est le meilleure façon d'atteindre cette fonctionnalité en python?


0 commentaires

4 Réponses :


2
votes

Coroutines (bassfriend les a mentionnés) sont difficiles pour les non initiés, alors voici un. J'ai ajouté du code de test pour que vous puissiez voir comment cela fonctionne vraiment. XXX

L'astuce est que si vous conservez les rôles de vos fonctions, où profond profond_first_search donne des nœuds, Vous vous retrouvez avec un horrible désordre ... à la place, les nœuds sont produits et envoyés au consommateur.

La prise en charge de Python pour les coroutines est un peu maladroite ( @coroutine à la rescousse). Il y a une jolie Nice Tutoriel pour Python et beaucoup de ressources pour les langues qui dépendent des coroutine, telles que Lua. De quelque manière que ce soit, c'est un concept très cool qui mérite d'explorer: -)


0 commentaires

2
votes

Normalement, vous ne dites pas votre iérien em> à vérifier les conditions, vous faites cela dans le corps de votre boucle:

for node, depth in graph.depth_first_search():
    if node meets condition:
        # do something with node 
        break
# do something with node, its still referencing what you breaked on


1 commentaires

Non, cela ne fonctionnerait pas, car cela empêcherait la boucle complètement. Ici, nous voulons arrêter l'algorithme de chercher plus profondément dans la branche actuelle, mais il reste peut-être d'autres branches à explorer. Voir Profondeur-première recherche .



4
votes

solution naïf: xxx

Vous pouvez l'appeler normalement toujours, mais vous devez sauvegarder le démonteur pour avorter: xxx

i pense que cela fonctionne en ce moment.


5 commentaires

Ceci est en fait un moyen courant de gâcher: it.send (1) envoie le 1, comme prévu, mais continue également it à l'élément suivant - que vous seriez juste ignorer. Fondamentalement, vous devez dupliquer la boucle entière à nouveau dans le bloc de cesser de fumer, encore et encore. En fait, vous ne pouvez jamais mélanger l'envoi et l'itération de la même chose (vous traiteriez la chose en tant que générateur et une coroutine en même temps, ce qui n'a aucun sens).


Bien fixé, mais vous voulez break au lieu de retour dans profond profond_first_search


Si nous voulons abandonner le générateur complètement (ce que j'étais codé pour), nous avons besoin de retour car il y a 2 pour boucles.


Merci beaucoup pour vos réponses, David X et THC4K. Les coroutines sont en effet ce dont j'avais besoin. Puisqu'il.send (1) attend une réponse, un rendement supplémentaire est effectivement nécessaire ... Cette solution fait un it.Sutume () (implicite de la boucle de la boucle) et une it.send (1) lorsque la condition est rencontré. Ce serait bien de l'utiliser (1) ou it.send (0) Au lieu de cela, mais malheureusement, vous perdez la possibilité d'utiliser A pour boucle et que vous êtes obligé d'utiliser une boucle de temps. (Remarque: une pause est en effet nécessaire au lieu d'un retour si vous voulez explorer les nœuds restants)


@Mathieu, oh, donc c'est ce que le pause est pour; a du sens maintenant, merci. (Aussi it.next () est équivalent à it.send (aucun) si la mémoire sert.)



19
votes

généralement dans Python, vous arrêteriez simplement de consommer le générateur et d'oublier. Point. (Ainsi, laissant des choses à la poubelle de la manière habituelle)

à l'aide de générateur.close () Vous pouvez forcer un nettoyage de générateur immédiat déclenchant immédiatement toutes les finalisations.

: xxx