Является ли generator.next () видимым в Python 3?

247

У меня есть генератор, который генерирует серию, например:

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

В Python 2 я могу сделать следующие звонки:

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

однако в Python 3, если я выполняю те же две строки кода, я получаю следующую ошибку:

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

но синтаксис итератора цикла работает в Python 3

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

Я пока не смог найти ничего, что объясняет эту разницу в поведении для Python 3.

jottos
источник

Ответы:

406

g.next()был переименован в g.__next__(). Причиной этого является последовательность: специальные методы, такие как __init__()и __del__()все, имеют двойное подчеркивание (или «недоумение» в текущем народном языке) и .next()были одним из немногих исключений из этого правила. Это было исправлено в Python 3.0. [*]

Но вместо звонка g.__next__()используйте next(g).

[*] Есть другие специальные атрибуты, которые получили это исправление; func_nameсейчас __name__и т. д.

Леннарт Регебро
источник
Любая идея, почему Python 2 отказался от соглашения Dunder для этих методов в первую очередь?
Рик поддерживает Монику
Это, вероятно, просто недосмотр.
Леннарт Регебро
Как насчет того, чтобы перезаписывать __str __ в классах? Это меняет str (obj) или __str __ (obj)?
NoName
@ NoName Нет такой вещи __str__(obj), так что я не совсем понимаю вопрос.
Леннарт Регебро
1
@ NoName Да, вы делаете.
Леннарт Регебро,
144

Пытаться:

next(g)

Посмотрите на эту аккуратную таблицу, которая показывает различия в синтаксисе между 2 и 3, когда дело доходит до этого.

Паоло Бергантино
источник
1
@MaikuMori Я исправил ссылку (в ожидании рецензирования) (сайт diveintopython3.org, кажется, не работает. Зеркальный сайт diveintopython3.ep.io еще жив)
gecco
1
Исправлена ​​ссылка снова. python3porting.com/differences.html является более полным, кстати.
Леннарт Регебро
Есть ли какое-то оправдание для перехода от метода к функции, помимо того, что g.next()должно быть на самом деле g.__next__(), и нам нужно что-то, что не является более сложным методом с функциональностью g.next()?
Проктор ТК
11

Если ваш код должен работать под Python2 и Python3, используйте библиотеку 2to3 six, например:

import six

six.next(g)  # on PY2K: 'g.next()' and onPY3K: 'next(g)'
danius
источник
18
В этом нет особой необходимости, если только вам не требуется поддержка версий Python ранее 2.6. Python 2.6 и 2.7 имеют nextвстроенную функцию.
Марк Дикинсон