¿Es generador.next () visible en Python 3?

247

Tengo un generador que genera una serie, por ejemplo:

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

En Python 2 puedo hacer las siguientes llamadas:

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

sin embargo, en Python 3 si ejecuto las mismas dos líneas de código me sale el siguiente error:

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

pero, la sintaxis del iterador de bucle funciona en Python 3

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

Todavía no he podido encontrar nada que explique esta diferencia de comportamiento para Python 3.

jottos
fuente

Respuestas:

406

g.next()ha cambiado de nombre a g.__next__(). La razón de esto es la coherencia: los métodos especiales como __init__()y __del__()todos tienen guiones bajos dobles (o "dunder" en la lengua vernácula actual), y .next()fue una de las pocas excepciones a esa regla. Esto se solucionó en Python 3.0. [*]

Pero en lugar de llamar g.__next__(), use next(g).

[*] Hay otros atributos especiales que han obtenido esta solución; func_name, es ahora __name__, etc.

Lennart Regebro
fuente
¿Alguna idea de por qué Python 2 evitó la convención Dunder para estos métodos en primer lugar?
Rick apoya a Monica el
Probablemente sea solo un descuido.
Lennart Regebro
¿Qué pasa cuando sobrescribe __ str __ en las clases? ¿Cambia str (obj) o __str __ (obj)?
NoName
@NoName No existe tal cosa __str__(obj), así que realmente no entiendo la pregunta.
Lennart Regebro
1
@NoName Sí, lo haces.
Lennart Regebro
144

Tratar:

next(g)

Consulte esta tabla ordenada que muestra las diferencias de sintaxis entre 2 y 3 cuando se trata de esto.

Paolo Bergantino
fuente
1
@MaikuMori Arreglé el enlace (esperando la revisión por pares) (El sitio diveintopython3.org parece estar inactivo. El sitio espejo diveintopython3.ep.io todavía está vivo)
gecco
1
Se corrigió el enlace nuevamente. python3porting.com/differences.html es más completo, por cierto.
Lennart Regebro
¿Existe alguna justificación para el cambio de un método a una función, más allá de lo g.next()que realmente debería ser g.__next__(), y necesitamos tener algo que no sea un método dunder con la funcionalidad de g.next()?
TC Proctor
11

Si su código debe ejecutarse en Python2 y Python3, use la biblioteca 2to3 six de esta manera:

import six

six.next(g)  # on PY2K: 'g.next()' and onPY3K: 'next(g)'
danius
fuente
18
No hay mucha necesidad de esto a menos que necesite admitir versiones de Python anteriores a la 2.6. Python 2.6 y 2.7 tienen la nextfunción incorporada.
Mark Dickinson