Generator.next () é visível no Python 3?

247

Eu tenho um gerador que gera uma série, por exemplo:

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

No Python 2, posso fazer as seguintes chamadas:

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

no entanto, no Python 3, se eu executar as mesmas duas linhas de código, recebo o seguinte erro:

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

mas, a sintaxe do iterador de loop funciona no Python 3

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

Ainda não consegui encontrar nada que explique essa diferença de comportamento no Python 3.

jottos
fonte

Respostas:

406

g.next()foi renomeado para g.__next__(). A razão para isso é a consistência: métodos especiais como __init__()e __del__()todos têm sublinhados duplos (ou "dunder" no vernáculo atual) e .next()foram uma das poucas exceções a essa regra. Isso foi corrigido no Python 3.0. [*]

Mas, em vez de ligar g.__next__(), use next(g).

[*] Existem outros atributos especiais que receberam essa correção; func_name, É agora __name__, etc.

Lennart Regebro
fonte
Alguma idéia de por que o python 2 evitou a convenção do dunder para esses métodos?
Rick suporta Monica
Provavelmente isso é apenas um descuido.
Lennart Regebro 31/03
E quando você sobrescreve __ str __ nas aulas? Ele muda str (obj) ou __str __ (obj)?
NoName 27/10/19
@NoName Não existe __str__(obj), então eu realmente não entendo a pergunta.
Lennart Regebro 29/10/19
1
@NoName Sim, você faz.
Lennart Regebro 30/10/19
144

Experimentar:

next(g)

Confira esta tabela elegante que mostra as diferenças de sintaxe entre 2 e 3 quando se trata disso.

Paolo Bergantino
fonte
1
@MaikuMori I fixou o link (à espera de revisão pelos pares) (O site diveintopython3.org parece ser baixo Mirror site. Diveintopython3.ep.io ainda está vivo)
Gecco
1
Corrigido o link novamente. python3porting.com/differences.html é mais completo, aliás.
Lennart Regebro
Existe alguma justificativa para a mudança de um método para uma função, além do g.next()que realmente deveria ser g.__next__(), e precisamos ter algo que não seja um método obscuro com a funcionalidade de g.next()?
TC Proctor
11

Se seu código deve ser executado em Python2 e Python3, use a biblioteca 2to3 six como esta:

import six

six.next(g)  # on PY2K: 'g.next()' and onPY3K: 'next(g)'
danius
fonte
18
Não há muita necessidade disso, a menos que você precise suportar versões do Python anteriores à 2.6. Python 2.6 e 2.7 têm a nextfunção interna.
Mark Dickinson