IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

itérer plusieurs fois sur un iterateur


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Creuse (Limousin)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 11
    Par défaut itérer plusieurs fois sur un iterateur
    Bonjour,
    j'ai une classe MonIter (tirée d'un exemple trouvé sur le web) qui doit me permettre d'itérer sur les n premiers entiers (n étant fournie en argument du constructeur à l'instanciation).

    Pour être plus précis, dans mon cas réel, j'ai une classe GribFile (décrivant un certain format de fichier) qui permet d'itérer sur des objets de type GribMessage (correspondant à tous les messages d'un fichier)

    J'ai fait une methode __setitem__ dont le but est pour chaque élément de l'itération d'affecter à la clé k la valeur v. J'itère donc sur ces valeurs. Seul problème, quand j'ai fini d'itérer, je ne peux plus réitérer.
    J'ai lu des choses sur itertools.tee, mais je ne vois pas comment l'utiliser dans ce cas.
    Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import print_function
     
     
    class MonIter():
     
        current=0
     
        def __init__(self,stop):
            self.stop=stop
     
        def __iter__(self) :
            return self
     
        def __setitem__(self,key,val):
          for i in self:
            print("si je pouvais sur le message "+str(i)+" je ferais : "+str(i)+"["+str(key)+"]"+str(val))
     
        def next(self) :
            self.current+= 1
     
            if self.current>self.stop:
                raise StopIteration
     
            if self.current == 5:
              print("Quoi déjà 5eme tour?")
     
            return self.current
     
    i1=MonIter(6)
    #for i in i1:
    #  print(i)
     
    i1["truc"]="chose"
     
    for i in i1: # ca marche pas, je suis deja a la fin de l iteration a cause de mon passage dans __setitem__ lors de l'affectation precedente
      print(i)
    Quelqu'un peut il m'éclairer ?
    Mon objectif est de pouvoir arriver à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    with GribFile(nomfichier) as g:
      g[k]=v # Affecte la valeur v aux cles k de chacun des messages contenus dans g
      for m in g # Boucle sur les messages
        # faire des super choses
    plutôt que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    with GribFile(nomfichier) as g:
      for m in g # Boucle sur les messages
        m[k]=v
        # faire des super choses
    Entre parenthèses je m'en sors très bien avec cette dernière syntaxe mais je préférerais la première (qui devrait faire exactement la même chose au final)
    Merci

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 831
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 831
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par zequiche Voir le message
    Mon objectif est de pouvoir arriver à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    with GribFile(nomfichier) as g:
      g[k]=v # Affecte la valeur v aux cles k de chacun des messages contenus dans g
      for m in g # Boucle sur les messages
        # faire des super choses
    plutôt que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    with GribFile(nomfichier) as g:
      for m in g # Boucle sur les messages
        m[k]=v
        # faire des super choses
    Entre parenthèses je m'en sors très bien avec cette dernière syntaxe mais je préférerais la première (qui devrait faire exactement la même chose au final)
    Bonjour

    Ne sachant pas trop ce qu'était un "GribFile", ni ce que représentait "k" pour toi, j'ai déduit de ton "for" final qu'un GribFile était une liste de dictionnaires.
    Je suis parti de ce postulat et écrit un exemple de GribFile perso qui stocke le fichier "/etc/passwd" sous la même forme (les lignes sont transformées en dictionnaire et stockées dans un tableau).

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    class GribFile(object):
        def __init__(self):
            self.__current=0
            with open("/etc/passwd", "r") as fp:
                self.__data=[
                    dict(
                        zip(
                            ("login", "passwd", "uid", "gid", "comment", "home", "shell"),
                            lig.replace("\n", "").split(":"),
                        )
                    ) for lig in fp
                ]
            # with
        # __init__()
     
        def __iter__(self): return self
     
        def __setitem__(self, k, v):
            c=self.__current
            for lig in self: lig[k]=v
            self.__current=c
        # __setitem__()
     
        def seek(self, n=0): self.__current=n
     
        def next(self):
            if self.__current >= len(self.__data):
                raise StopIteration
     
            data=self.__data[self.__current]
            self.__current+=1
            return data
        # next()
     
        # Ca c'est pour que le GribFile puisse être utilisé dans un "with"
        def __enter__(self): return self
        def __exit__(self, *args): pass
    # class GribFile
     
    with GribFile() as g:
        g["login"]="toto"
        for m in g: print m
    # with

    En espérant que ça te convienne.

    PS: La méthode "seek" n'est pas utilisée mais elle permet de repositionner ton itérateur sur l'itération de ton choix.
    P2: Ca fonctionne mais je ne suis pas certain que tu gagnes en clarté. Parce que celui qui va lire le code sans connaitre le GribFile, ne pigera pas pourquoi la ligne g["login"]="toto" affecte toutes les lignes
    PS3: pour faire fonctionner ton premier exemple, il suffisait juste de mémoriser le current en début de __setitem__ et le restaurer à la fin (comme j'ai fait ici). Accessoirement la ligne "current=0" au tout début est totalement malvenue (j'aimerais bien connaitre la source de ce truc) car current est utilisé comme membre d'instance et non comme membre de classe. En fait ça fonctionne parce que le premier "next" l'incrémente en tant que "self" mais si on remplace self.current par MonIter.current (comme c'est autorisé avec les membres de classes) et qu'on veut gérer deux itérateurs distincts i1 et i2 ben le truc explose en vol. Il aurait fallu le mettre en réalité dans le __init__ en tant que "self.current=0".
    PS4: j'adore ton pseudo...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2017
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Creuse (Limousin)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2017
    Messages : 11
    Par défaut
    Merci de ta réponse. Je suis bien convaincu par ton code.
    Tu as bien supposé, c'est équivalent à un itérateur sur des dictionnaires avec des clés communes.
    Mais, au final, et comme tu dis, c'est peut être plus clair quand on lit le code de voir l'affectation pour chaque message (ou dictionnaire dans ton cas).
    Intéressant, en tous cas.
    Quant à la source du code je ne retrouve plus le site, je verrai sur mon autre bécane demain, ça doit être dans l'historique.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 831
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 831
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par zequiche Voir le message
    Quant à la source du code je ne retrouve plus le site, je verrai sur mon autre bécane demain, ça doit être dans l'historique.
    Mouais. Bof, c'est pas vraiment grave. De toute façon je vais pas aller là bas leur dire que leur code est assez vaseux.
    Par exemple je m'en suis inspiré pour mon "__setitem__()", lequel itère sur "self" ce qui appelle "__iter__()" puis "next()". Lequel "next()" modifie "self.__current" ce qui m'oblige à le sauvegarder puis le restaurer.

    Mais si on itère directement sur "self.__data", ben tout ça disparait.

    Ce qui donne plus simplement
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def __setitem__(self, k, v):
         for lig in self.__data: lig[k]=v
    Au final ça se comporte pareil.

    Bon bref on retombe sur le dilemne assez classique du "vaut-il mieux utiliser les méthodes de la classe dans d'autres méthodes de classe" (on centralise les actions mais on surcharge la pile des appels) ou bien "vaut-il mieux travailler directement sur les membres de la classe"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. meme opérations plusieurs fois sur un fichier
    Par skouza dans le forum Entrée/Sortie
    Réponses: 3
    Dernier message: 26/08/2010, 11h29
  2. $.post s'éxecute plusieurs fois sur un event !
    Par toufou dans le forum jQuery
    Réponses: 5
    Dernier message: 03/03/2010, 15h44
  3. Réponses: 1
    Dernier message: 10/02/2009, 21h30
  4. Cliquer plusieurs fois sur Annuler
    Par Spani dans le forum Macros et VBA Excel
    Réponses: 8
    Dernier message: 14/08/2007, 11h06
  5. bouton entree plusieurs fois sur un form
    Par lili2704 dans le forum Struts 1
    Réponses: 5
    Dernier message: 29/06/2007, 14h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo