Как стать автором
Обновить

Комментарии 13

не стоит путать «генераторы коллекций» (comprehensions, они же «включения»)

Смущает терминология: что же здесь всё-таки имелось в виду? generator expressions или list comprehensions?

Объекты-генераторы

Это уже третья сущность :)

Я, видимо, не так понял вопрос. Статья про объекты генераторы, которые получаются из функций, внутри которых есть yield. Так же объекты-генераторы дают генераторные выражения (generator expression).

Смущает терминология: что же здесь всё-таки имелось в виду? generator expressions или list comprehensions?

Не очень понял, что тут смутило: генераторы коллекций — это генераторы списков (list comprehensions) + генераторы множеств + генераторы словарей.

Слова с корнем "генератор" перегружены разными смыслами. Не случайно в англоязычной литературе пишут "list comprehension", а не "list generator".


Допустим у нас есть вот такой класс:


class MyIterable:
    def __init__(this):
        this.value = 0
    def __iter__(this):
        return this
    def __next__(this):
        this.value += 1
        print("Current value", this.value)
        if this.value < 5:
            return this.value
        else:
            raise StopIteration

Затем используем его в list comprehension:


>>> l = [a for a in MyIterable()]
>>> print(l)
Current value 1
Current value 2
Current value 3
Current value 4
Current value 5
[1, 2, 3, 4]
>>> for i in l:
>>>     print(i)
1
2
3
4

А теперь поиграемся в генераторы


>>> g = (a for a in MyIterable())
>>> print(g)
<generator object <genexpr> at 0x7f341679dc10>
>>> for i in g:
>>>     print(i)
Current value 1
1
Current value 2
2
Current value 3
3
Current value 4
4
Current value 5

Мы получили генератор, но не использвали yield.


Ну, и вообще термин "генератор-итератор" меня, мягко говоря, вводит в ступор. Что уж говорить о самых маленьких :) Я-то думал, что Generator — это одно, а Iterator — это немножко другое.

генератор — частный случай итератора) поэтому и решил писать об этом, как об итераторе-генераторе, потому что итератор может быть реализован и в виде кастомного класса. По поводу того, что понятий после перевода напутали — очень плюсую, собственно очень хочется всё по полкам и разложить, спасибо за замечание, подумаю, как лучше исправить!
генератор — частный случай итератора

Не совсем так. Генератор — это функция, которая возвращает итератор. В свою очередь итератор — это не функция, а объект, который семантически представляет собой поток данных и имплементирует итераторный протокол (т.е. имеет методы __iter__() и, самое главное, __next__()).


Действительно, есть ещё "generator iterator". Но это не генератор-итератор, а скорее генераторный итератор по-русски, т.е. итератор изготовленный генератором. В тексте статьи он назван generator object. Видимо потому, что такое название выдаёт его метод __str__().


Вообще, перед тем, как рассказать маленьким об итераторах и генераторах, лучше начать с ленивых (отложенных) вычислений и санок (thunks). Потому как итераторы — это именно что синтаксический сахар, и аналогичный эффект может быть достигнут и без yield, и без генераторных выражений. Мне этим питон не нравится в качестве языка для обучения CS — скрывает фундаментальные вещи за сахаром.

Думаю, имелись в виду сollection сomprehensions, которые есть как у list, так и у dict и set. И generator expression, и полновесные генераторы-функции возвращают generator object.

Нормальный путь питониста вглубь этой темы:

  1. Не знать про yield. Спокойно в своём уютненьком юпитер-нотбуке совать пандас в матплотлиб и горя не знать.

  2. Вау, оказывается, можно не один раз отдавать результат из функции, а несколько раз. Или вообще много раз. Или, хе-хе, бесконечность раз. Прикол. Непонятно, правда, зачем оно может быть нужно.

  3. Разобрались зачем это нужно, вошли во вкус, пользуемся. Возможность выстраивать логику программы не от источника данных, а наоборот, от потребителя - действительно иногда удобно. Да что там говорить, почти всегда удобнее.

  4. Оказывается, yield умеет не только отдавать, но ещё и принимать данные. Ой.

  5. Туго, со скрипом, через боль и фрустрацию въезжаем в тему async/await и внезапно обнаруживаем, что теперь у нас каждая мать её функция является этим самым генератором, который где-то там внутри под капотом елдячит на каждом "await".

  6. ... не знаю, я дальше не ходил.

Спасибо, очень понятно написано. Параллель с Тридевятым царством и Вовкой прекрасна!

спасибо! Очень рад, что понравилось! постараюсь и дальше радовать контентом)
Спасибо за объяснение генераторов. Вероятно, опечатка закралась в функции second_eater и third_eater: eda = next(skat) должно быть внутри цикла while.
спасибо большое! Я обязательно исправлю!
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.