Le générateur.next () est-il visible dans Python 3?

247

J'ai un générateur qui génère une série, par exemple:

def triangle_nums():
    '''Generates a series of triangle numbers'''
    tn = 0
    counter = 1
    while True:
        tn += counter
        yield tn
        counter += + 1

En Python 2, je peux faire les appels suivants:

g = triangle_nums()  # get the generator
g.next()             # get the next value

cependant en Python 3 si j'exécute les deux mêmes lignes de code j'obtiens l'erreur suivante:

AttributeError: 'generator' object has no attribute 'next'

mais, la syntaxe de l'itérateur de boucle fonctionne en Python 3

for n in triangle_nums():
    if not exit_cond:
       do_something()...

Je n'ai encore rien trouvé qui explique cette différence de comportement pour Python 3.

jottos
la source

Réponses:

406

g.next()a été renommé en g.__next__(). La raison en est la cohérence: les méthodes spéciales comme __init__()et __del__()toutes ont des doubles soulignements (ou "dunder" dans la langue vernaculaire actuelle), et ont .next()été l'une des rares exceptions à cette règle. Cela a été corrigé dans Python 3.0. [*]

Mais au lieu d'appeler g.__next__(), utilisez next(g).

[*] Il existe d'autres attributs spéciaux qui ont obtenu ce correctif; func_name, c'est maintenant __name__, etc.

Lennart Regebro
la source
une idée pourquoi python 2 a évité la convention dunder pour ces méthodes en premier lieu?
Rick soutient Monica
Ce n'est probablement qu'un oubli.
Lennart Regebro
Qu'en est-il lorsque vous écrasez __ str __ dans les classes? Cela change-t-il str (obj) ou __str __ (obj)?
NoName
@NoName Il n'y a rien de tel __str__(obj), donc je ne comprends pas vraiment la question.
Lennart Regebro
1
@NoName Oui, vous le faites.
Lennart Regebro
144

Essayer:

next(g)

Consultez ce tableau soigné qui montre les différences de syntaxe entre 2 et 3 en ce qui concerne cela.

Paolo Bergantino
la source
1
@MaikuMori J'ai corrigé le lien (en attente de révision par les pairs) (Le site diveintopython3.org semble être en panne. Le site miroir diveintopython3.ep.io est toujours vivant)
gecco
1
Correction du lien à nouveau. python3porting.com/differences.html est plus complet, btw.
Lennart Regebro
Y a-t-il une justification pour le passage d'une méthode à une fonction, au-delà g.next()devrait être vraiment g.__next__(), et nous avons besoin d'avoir quelque chose qui n'est pas une méthode stupide avec la fonctionnalité de g.next()?
TC Proctor
11

Si votre code doit s'exécuter sous Python2 et Python3, utilisez la bibliothèque 2to3 six comme ceci:

import six

six.next(g)  # on PY2K: 'g.next()' and onPY3K: 'next(g)'
danius
la source
18
Cela n'est pas vraiment nécessaire, sauf si vous devez prendre en charge les versions Python antérieures à 2.6. Python 2.6 et 2.7 ont la nextfonction intégrée.
Mark Dickinson