Czy generator.next () jest widoczny w Pythonie 3?

247

Mam generator, który generuje serię, na przykład:

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

W Pythonie 2 jestem w stanie wykonywać następujące połączenia:

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

jednak w Pythonie 3, jeśli wykonam te same dwa wiersze kodu, pojawia się następujący błąd:

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

ale składnia iteratora pętli działa w Pythonie 3

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

Nie byłem jeszcze w stanie znaleźć niczego, co wyjaśniałoby tę różnicę w zachowaniu dla Pythona 3.

jottos
źródło

Odpowiedzi:

406

g.next()został przemianowany na g.__next__(). Powodem tego jest konsekwencja: specjalne metody, takie jak __init__()i __del__()wszystkie, mają podwójne znaki podkreślenia (lub „dunder” w obecnej wersji językowej) i .next()były jednym z niewielu wyjątków od tej reguły. Zostało to naprawione w Python 3.0. [*]

Ale zamiast dzwonić g.__next__(), użyj next(g).

[*] Istnieją inne specjalne atrybuty, które uzyskały tę poprawkę; func_nameJest teraz __name__, etc.

Lennart Regebro
źródło
jakiś pomysł, dlaczego python 2 po pierwsze zrezygnował z konwencji dundera dotyczącej tych metod?
Rick wspiera Monikę
To prawdopodobnie tylko niedopatrzenie.
Lennart Regebro
Co powiesz na to, kiedy zastąpisz __ str __ na zajęciach? Czy zmienia str (obj) czy __str __ (obj)?
NoName
@NoName Nie ma czegoś takiego jak __str__(obj), więc tak naprawdę nie rozumiem pytania.
Lennart Regebro
1
@NoName Tak, robisz.
Lennart Regebro
144

Próbować:

next(g)

Sprawdź tę zgrabną tabelę, która pokazuje różnice w składni między 2 a 3, jeśli chodzi o to.

Paolo Bergantino
źródło
1
@MaikuMori Naprawiłem link (czekam na wersję peer) (Strona diveintopython3.org wydaje się nie działać. Strona lustrzana diveintopython3.ep.io wciąż żyje)
gecco
1
Naprawiono link ponownie. python3porting.com/differences.html jest bardziej kompletny, btw.
Lennart Regebro
Czy jest jakieś uzasadnienie dla przejścia z metody na funkcję, poza nią g.next()naprawdę powinno być g.__next__(), i musimy mieć coś, co nie jest metodą dundera z funkcjonalnością g.next()?
TC Proctor,
11

Jeśli twój kod musi działać w Python2 i Python3, użyj biblioteki 2to3 six w następujący sposób:

import six

six.next(g)  # on PY2K: 'g.next()' and onPY3K: 'next(g)'
Danius
źródło
18
Nie ma takiej potrzeby, chyba że potrzebujesz obsługi wersji Python wcześniejszych niż 2.6. Python 2.6 i 2.7 mają nextwbudowaną funkcję.
Mark Dickinson