Itérer "discrètement" sur un élément

Itérer "discrètement" sur un élément - Python - Programmation

Marsh Posté le 05-03-2009 à 12:05:05    

Bonjour,
 
Dans le cadre d'une itération sur un élément, je souhaite savoir comment itérer "discrètement", sans instancier de variable inutile. J'explique :  
J'ai quelque part une classe implémentant un algorithme séquenciel. Cet algorithme avance étape par étape par un appel à un générateur implicite (dans le cas présent, considérons qu'un appel à "next" sur un objet issu de cette classe fournisse un itérateur faisant évoluer l'algorithme étape par étape). Cette méthode ne retourne rien, seul l'état interne de l'algo est modifié à chaque étape.  
 
La façon la plus évidente et la plus simple d'obtenir le résultat final de cet algorithme semble être :

Code :
  1. for x in algo.next():
  2.   pass


Où est le problème ? En réalité, il n'y en a pas : ça fonctionne, c'est suffisament explicite mais... par convention, les outils de vérification de code signalent qu'il y a une variable inutilisée "x". Alors, ce n'est pas un problème en soit, mais c'était suffisant pour attiser ma curiosité :  
 - Quelles seraient les méthodes alternatives pour parcourir l'ensemble d'un itérable (attention, ça peut être un générateur sans sentinelle, donc pas de builtin iter(iterable, sentinel) ici) sans avoir une variable inutilisée ?
 
Bien entendu, je souhaiterai que tout cela reste lisible, explicite et concis (donc pas de map avec une fonction identité, par exemple).

Reply

Marsh Posté le 05-03-2009 à 12:05:05   

Reply

Marsh Posté le 05-03-2009 à 12:22:36    

  • Appeler next() n'a aucun intérêt ici, si algo est un itérable, alors for x in algo: pass est largement suffisant pour effectuer l'itération intégrale.
  • Il est possible de forcer l'évaluation d'un itérateur en le transformant en liste (list(algo)), malheureusement ça n'est pas nécessairement clair sur le but de l'opération, dans la mesure où aucune liste ne sera récupérée ou utilisée.
  • Le plus clair serait probablement de créer une fonction evaluate (pouvant être simplement définie comme evaluate = list, ou evaluate = functools.partial(map, lambda _: None)) qui servira à forcer l'évaluation de l'itérateur.


Enfin, iter ne sert de toute façon pas à forcer une évaluation, aucun intérêt ici.

 

Enfin, je ne vois pas l'intérêt de présenter l'algo sous la forme d'un itérateur si on ne peut rien en faire et si l'itérateur ne sert à rien.

Message cité 1 fois
Message édité par masklinn le 05-03-2009 à 12:23:57

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 05-03-2009 à 12:42:14    

masklinn a écrit :

  • Appeler next() n'a aucun intérêt ici, si algo est un itérable, alors for x in algo: pass est largement suffisant pour effectuer l'itération intégrale.
  • Il est possible de forcer l'évaluation d'un itérateur en le transformant en liste (list(algo)), malheureusement ça n'est pas nécessairement clair sur le but de l'opération, dans la mesure où aucune liste ne sera récupérée ou utilisée.
  • Le plus clair serait probablement de créer une fonction evaluate (pouvant être simplement définie comme evaluate = list, ou evaluate = functools.partial(map, lambda _: None)) qui servira à forcer l'évaluation de l'itérateur.

)


 - Comme je l'ai dit, next() ne fait que retourner un itérateur, c'est pour l'exemple. Effectivement, un objet issu de cette classe modélisant ma séquence est itérable et "in algo" est largement suffisant.  
 - Le problème en passant par une liste (que ce soit via une compréhension ou ta fonction partielle reposant sur un map), c'est l'espace occupé en mémoire. La séquence pouvant être (potentiellement infiniment) longue. Repasser par un générateur ne ferait que déplacer le problème. Un reduce serait plus adapté, d'un point de vue consommation, mais tout aussi peu clair.  
 
 
 
Présenter l'algorithme sous forme d'itérateur me permet d'analyser chaque étape de l'algorithme (je rappelle qu'il s'agit de la construction d'une séquence) en vérifiant l'état interne de l'objet (état qui serait trop conséquent à fournir en output de l'itérateur ou à mémoriser complètement). L'exemple du premier message n'est qu'un cas particulier dans lequel je souhaite obtenir le résultat de cet algorithme sans considérer chacune des étapes.

Reply

Marsh Posté le 05-03-2009 à 12:48:19    

guybrush02 a écrit :

- Le problème en passant par une liste (que ce soit via une compréhension ou ta fonction partielle reposant sur un map), c'est l'espace occupé en mémoire. La séquence pouvant être (potentiellement infiniment) longue. Repasser par un générateur ne ferait que déplacer le problème. Un reduce serait plus adapté, d'un point de vue consommation, mais tout aussi peu clair.


Je ne vois pas ce qui t'empeche d'adapter la 3e proposition en définissant evaluate différement. Ca peut être à base de reduce, ou avec une boucle for qui ne fait rien, aucune importance [:petrus75]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 05-03-2009 à 12:55:13    

masklinn a écrit :


Je ne vois pas ce qui t'empeche d'adapter la 3e proposition en définissant evaluate différement. Ca peut être à base de reduce, ou avec une boucle for qui ne fait rien, aucune importance [:petrus75]


C'est pas faux  :)  
Mais définir une fonction evaluate juste pour dire de ne pas avoir une variable inutilisée, bof :-)
J'avoue, ma question initiale est purement académique. J'imaginais qu'il devait me manquer une petite astuce en Python permettant d'itérer sans variable.  
 
En fait, après réflexion, la question initiale pourrait être formulée plus simplement :  
Soit g un buffer/générateur, comment épuiser g ?  
 
... et les réponses seraient les mêmes :-)

Reply

Marsh Posté le 05-03-2009 à 13:00:06    

guybrush02 a écrit :

Mais définir une fonction evaluate juste pour dire de ne pas avoir une variable inutilisée, bof :-)


Ne pas avoir une variable inutilisée, et exprimer clairement que l'intérêt réside dans les effets de bord générés par l'itérateur et non dans les valeurs retournées par celui-ci [:spamafote]

guybrush02 a écrit :

J'imaginais qu'il devait me manquer une petite astuce en Python permettant d'itérer sans variable.


Je n'ai jamais eu un besoin pareil, je présume que la grande majorité de la communauté Python est dans ce cas, et les rares fois où ce cas est rencontré ils appellent simplement list, ou une variante.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 05-03-2009 à 18:44:35    

Si tu peux implementer une fonction has_next, une solution propre et programmatiquement élégante pourrait etre :
 

Code :
  1. while ( algo.has_next() ):
  2.     algo.next()

Reply

Marsh Posté le 05-03-2009 à 19:02:38    

elsed a écrit :

Si tu peux implementer une fonction has_next, une solution propre et programmatiquement élégante pourrait etre :
 

Code :
  1. while ( algo.has_next() ):
  2.     algo.next()



On a franchement pas les mêmes définitions de "propre" ou "programmatiquement élégant" [:pingouino]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 05-03-2009 à 19:39:25    

Pareil que Masklinn  :)
 
Edité : et même un while algo: pass ne serait pas élégant, bien que dans mon cas, il ne serait pas difficile de retourner une valeur de vérité :-)


Message édité par guybrush02 le 05-03-2009 à 19:40:50
Reply

Marsh Posté le 06-03-2009 à 10:16:09    

masklinn a écrit :


On a franchement pas les mêmes définitions de "propre" ou "programmatiquement élégant" [:pingouino]


 
 
son probleme n'est pas du tout un probleme d'iterateur :
 
en renommant les methodes ça paraitra peut-etre plus clair :
 
   1. while ( algo.has_next_step() ):
   2.     algo.execute_next_step()
 
y'a pas plus simple et plus lisible.

Reply

Marsh Posté le 06-03-2009 à 10:16:09   

Reply

Marsh Posté le 06-03-2009 à 10:37:22    

elsed a écrit :

y'a pas plus simple et plus lisible.


Code :
  1. algo.execute()


[:spamafote]


Message édité par masklinn le 06-03-2009 à 10:37:33

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 06-03-2009 à 10:42:06    


Code :
  1. def execute():
  2.    while ( algo.has_next_step() ):
  3.        algo.execute_next_step()


 
 
huhu !
 :)

Reply

Marsh Posté le 06-03-2009 à 10:45:57    

elsed a écrit :


Code :
  1. def execute():
  2.    while ( algo.has_next_step() ):
  3.        algo.execute_next_step()


 
 
huhu !
 :)


http://forum.hardware.fr/hfr/Progr [...] m#t1857943
[:draculax_tt]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 06-03-2009 à 12:29:29    

Ce que je fais, c'est déjà définir une méthode "apply" sur l'algo, et c'est le contenu de cette méthode qui pour l'instant ne fait qu'un simple for x in self: pass.  
 
Calculatoirement, cela me coute autant de vérifier l'existence d'une étape supplémentaire que de la calculer. (Et vu la nature de l'algorithme, que je n'ai pas détaillé, je ne peux pas me permettre de calculer l'étape suivante, vérifier si le résultat est cohérent, retourner l'étape actuelle, mémoriser la suivante ;).

Reply

Marsh Posté le 03-06-2009 à 15:08:30    

Pour éviter que les outils de vérification de code ralent si tu n'utilises pas la variable dans le bloc, il me semble que la convention est d'utiliser "_" comme nom de variable.
 
Cela dit, il y a surement un moyen plus joli pour faire fonctionner ton algo.

Reply

Marsh Posté le 03-06-2009 à 15:11:53    

Malheureusement, _ génère également un avertissement (deux, par ailleurs, car _ est considéré comme un nom de variable inapproprié).  
 
Pour l'algo, effectivement, il s'agit juste de sucre "syntaxique" pour le résultat. Mais la question était plutot d'ordre général que spécifique à ma "problématique".  
 
Merci ;)

Reply

Marsh Posté le 03-06-2009 à 15:13:56    

Tu utilises pylint ?

Reply

Marsh Posté le 03-06-2009 à 15:16:17    

Pychecker et pylint.  
Je ne sais plus de mémoire lequel (si ce n'est les deux ?) qui indiquait cela.

Reply

Marsh Posté le 03-06-2009 à 15:24:02    

Je parlais de ça en fait (retrouvé dans l'aide de pylint) :
 

   --dummy-variables-rgx=<regexp>
                        A regular expression matching names used
                        for dummy variables (i.e. not used). [current:
                        _|dummy]


 
Enfin bon si ça t'aides pas :)

Reply

Marsh Posté le 03-06-2009 à 15:36:11    

Curieux, j'ai l'erreur qui se produit encore (enfin, l'avertissement) et je ne trouve pas ton passage dans l'aide de pylint. Par contre, un tour sur la page man via Google me donne bien cela. Je vais mettre à jour, je suppose que cela vient de là.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed