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

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

Никогда не использовал, но, да, идея с parametrize и product очень интересная

The left-to-right evaluation order of the iterables is guaranteed. This makes possible an idiom for clustering a data series into n-length groups using zip(*[iter(s)]*n, strict=True). This repeats the same iterator n times so that each output tuple has the result of n calls to the iterator. This has the effect of dividing the input into n-length chunks. https://docs.python.org/3.11/library/functions.html#zip

a = [1, 2, 3, 4, 5, 6]
list(zip(*[iter(a)]*3))
[(1, 2, 3), (4, 5, 6)]

Есть ещё вот такой способ:

from itertools import islice

a = [1, 2, 3, 4, 5, 6]
iterator = iter(a)
list(iter(lambda: list(islice(iterator, 3)), []))
# [[1, 2, 3], [4, 5, 6]]

Вопрос к началу статьи. А что другие языке сейчас этого не умеют делать? Я спокойно тоже самое могу делать на C#, Lua, Delphi, Basic ...

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

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

Согласен, в каждом языке куча своих особенностей и подводных камней. Большую часть времени я работаю с Python, и мне нравится Python, поэтому статьи тоже про Python. Написать хорошую статью про язык, с которомы ты не работаешь, довольно сложно, если вообще возможно, на мой взгляд.

Редкий случай, когда статья оказалась лучше, чем то, что я ожидал, исходя из названия.

Рад, что статья понравилась, буду думать, как придумывать названия лучше)

Хорошая статья, всегда полезно такие вещи перечитывать даже когда вроде и шаришь и юзаешь давно и плотно, но нет-нет да и находится какая-то фишка или пояснение, нечто, на что ранее не обращал внимание или с чем не доводилось столкнуться.

Кстати, функция iter() с аргументом sentinel еще может быть полезна для организации длинных циклов заранее неизвестной длины с постусловием для выхода и использованием номера итерации внутри, вроде такого:

for idx, _ in enumerate(iter(int, 1)):
  ... # doing something

Фишка тут в том, что int() всегда возвращает ноль, поэтому стоп-слова терминального символа встречено не будет.

Может всё-таки лучше itertools.count(0) ?

А знаете ли вы ещё какие-нибудь интересные примеры итераторов и итерируемых объектов в стандартной библиотеке Python?

Обильное использование итераторов в коде, создаёт последующим поколениям разработчиков, кто будет заниматься сопровождением, множество не только увлекательных, но и не тривиальных задач. Как раз таких, про которые мы часто пишем в своих резюме.

fizzbuzzes = islice(zip(numbers, fizzes, buzzes), 100)

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

Переписывание кода на традиционные циклы, зачастую не только возвращает вам понятные стектрейсы в случае ошибок, возможность отладки в дебагере по шагам, но и делает его быстрее.

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

Читаемость это важное свойство. Не сочтите за критику, у вас классная статья с выразительными примерами.

fizzbuzzes = islice(zip(numbers, fizzes, buzzes), 100)

Если рассматривать данную конкретную строку, то я не представляю как её можно понятнее переписать. Да, последующим поколениям разработчиков возможно придётся заглянуть в документацию по стандартной библиотеке.

Тема конечно философская. Читабельность это не только про возможность специалисту разобраться как работает код. В идеале, глядя на код вы должны понимать исходную постановку задачи - что он должен делать. Одно из следствий - такой код проще поддерживать (не требуется отдельно писать документацию) и расширять (требования обычно меняются в тех же терминах, что и исходная постановка, значит код проще дорабатывать и верифицировать когда он написан в тех же терминах и общей логике).

если число делится нацело на 3, то вместо самого числа нужно вывести строку fizz, если же число делится нацело на 5, то нужно вывести строку buzz. Ну а если число делится нацело и на 3, и на 5, то на экран нужно вывести fizzbuzz

Здесь задача поставлена императивно. Поэтому реализация в виде кальки с if-else будет, на мой взгляд, наилучшей. Решение на итераторах элегантно остроумно. Но по сути это запись решения некоей эквивалентной задачи, поэтому оно довольно хрупкое. Глядя на код декомпилировать исходную постановку уже проблематично. Добавление новых условий в задачу сделает его или ещё более не эффективным или вообще заставит переписать целиком. Поэтому я сомневаюсь относительно читабельности.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории