web-dev-qa-db-fra.com

Pourquoi un objet itérable n'est-il pas un itérateur?

Voici mon code: 

from collections import deque

class linehistory:
    def __init__(self, lines, histlen=3):
        self.lines = lines
        self.history = deque(maxlen=histlen)

    def __iter__(self):
        for lineno, line in enumerate(self.lines,1):
            self.history.append((lineno, line))
            yield line

    def clear(self):
        self.history.clear()


f = open('somefile.txt')
lines = linehistory(f)
next(lines)

Erreur:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
    TypeError: 'linehistory' object is not an iterator

Je ne sais pas pourquoi l'objet linehistory n'est pas un itérateur puisqu'il a déjà inclus la méthode __iter__ dans la classe the.

13
pipi

En bref, "iterable" est l'objet que je veux parcourir. Il a __iter__().

Cependant, "itérateur" est l'objet utilisé pour l'itération. Il a next() ou __next__(). Comme tout itérateur est également itérable (étant son propre itérateur), il possède également __iter__().

Vous pouvez obtenir un itérateur pour tout objet itérable avec iter(obj).

Dans votre exemple, linehistory (qui devrait être écrit LineHistory) est itératif car il possède un _.__iter__(). L'objet générateur créé avec ceci est un itérateur (comme tout objet générateur).

13
glglgl

Réellement,

Toutes ces autres réponses sont fausses (sauf @glglgl qui a un style d'écriture obtus). Votre fonction de générateur __iter__() fonctionnerait telle quelle si vous l’appeliez avec une boucle for comme suit

for line in lines:
    print(line)

Mais comme vous avez utilisé next(lines), vous devez d’abord utiliser iter() pour obtenir l’itérateur (je suppose qu’il appelle simplement iter () sur l’objet) comme

it = iter(lines)
print(next(it))

comme M.Beazley fait remarquer

1
CpILL

Les objets Iterator nécessitent une méthode __iter__, mais ils doivent également avoir next implémenté:

Les objets itérateur eux-mêmes doivent prendre en charge les deux méthodes suivantes, qui forment ensemble le protocole itérateur:

itérateur .__ iter __ ()
Renvoie l'objet itérateur lui-même. 

iterator.next ()
Renvoie l'élément suivant du conteneur. 

Source Python 2.7

En Python 3.x, ce sont les noms de fonctions:

itérateur .__ iter __ () 

itérateur .__ suivant __ ()

Source Python 3.x

1
SuperBiasedMan