web-dev-qa-db-fra.com

Si range () est un générateur dans Python 3.3, pourquoi ne puis-je pas appeler next () sur une plage?

J'ai peut-être été victime de désinformation sur le Web, mais je pense qu'il est plus probable que j'ai mal compris quelque chose. D'après ce que j'ai appris jusqu'à présent, range () est un générateur et les générateurs peuvent être utilisés comme itérateurs. Cependant, ce code:

myrange = range(10)
print(next(myrange))

me donne cette erreur:

TypeError: 'range' object is not an iterator

Qu'est-ce que j'oublie ici? Je m'attendais à ce que cela affiche 0 et passe à la valeur suivante dans myrange. Je suis nouveau sur Python, alors veuillez accepter mes excuses pour la question plutôt basique, mais je n'ai trouvé aucune bonne explication ailleurs.

64
Jeff

range est une classe d'objets itérables immuables. Leur comportement d'itération peut être comparé à lists: vous ne pouvez pas appeler next directement sur eux; vous devez obtenir un itérateur en utilisant iter.

Donc non, range n'est pas un générateur.

Vous pensez peut-être, "pourquoi ne l'ont-ils pas rendu directement itérable"? Eh bien, ranges ont des propriétés utiles qui ne seraient pas possibles de cette façon:

  • Ils sont immuables, ils peuvent donc être utilisés comme clés de dictionnaire.
  • Ils ont les attributs start, stop et step (puisque Python 3.3), count et index méthodes et elles prennent en charge in, len et __getitem__ opérations.
  • Vous pouvez parcourir plusieurs fois la même range.

>>> myrange = range(1, 21, 2)
>>> myrange.start
1
>>> myrange.step
2
>>> myrange.index(17)
8
>>> myrange.index(18)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 18 is not in range
>>> it = iter(myrange)
>>> it
<range_iterator object at 0x7f504a9be960>
>>> next(it)
1
>>> next(it)
3
>>> next(it)
5
79
Oleh Prypin