HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <h2>Lazy Evaluation</h2>
1 <h2>Lazy Evaluation</h2>
2 <p><strong>Lazy Evaluation</strong>- это ленивые вычисления или отложенные вычисления, которые применяются в некоторых языках программирования. Это стратегия вычисления, согласно которой вычисления следует откладывать до тех пор, пока не понадобится их результат.</p>
2 <p><strong>Lazy Evaluation</strong>- это ленивые вычисления или отложенные вычисления, которые применяются в некоторых языках программирования. Это стратегия вычисления, согласно которой вычисления следует откладывать до тех пор, пока не понадобится их результат.</p>
3 <p>В реальности это касается не только языков. Это применяется и на уровне библиотек. Сейчас мы увидим, зачем это нужно, и как это работает.</p>
3 <p>В реальности это касается не только языков. Это применяется и на уровне библиотек. Сейчас мы увидим, зачем это нужно, и как это работает.</p>
4 <p>Ленивость в том или ином виде существует во всех языках программирования. В основном это касается логических выражений. И в Python она тоже есть.</p>
4 <p>Ленивость в том или ином виде существует во всех языках программирования. В основном это касается логических выражений. И в Python она тоже есть.</p>
5 <p>Например, если мы встречаем такое логическое выражение, то его выполнение идет слева направо:</p>
5 <p>Например, если мы встречаем такое логическое выражение, то его выполнение идет слева направо:</p>
6 <p>Если мы проверяем True, и далее стоит оператор "или" (or), то нам неважно, что будет справа. Эта часть кода не повлияет на то, что результатом будет истина.</p>
6 <p>Если мы проверяем True, и далее стоит оператор "или" (or), то нам неважно, что будет справа. Эта часть кода не повлияет на то, что результатом будет истина.</p>
7 <p>Это такая стратегия оптимизации внутри, которая позволяет не вычислять правое значение. Программисты пользуются этим, чтобы проверять существование какого-то объекта, например, что он не равен None, и вызывать дальше какой-то метод. Эта проверка на существование позволяет не писать сложные куски кода.</p>
7 <p>Это такая стратегия оптимизации внутри, которая позволяет не вычислять правое значение. Программисты пользуются этим, чтобы проверять существование какого-то объекта, например, что он не равен None, и вызывать дальше какой-то метод. Эта проверка на существование позволяет не писать сложные куски кода.</p>
8 <h2>Работа с коллекциями - итераторы</h2>
8 <h2>Работа с коллекциями - итераторы</h2>
9 <p>Основная область применения ленивых вычислений - работа с коллекциями. В Python есть встроенная функция reversed():</p>
9 <p>Основная область применения ленивых вычислений - работа с коллекциями. В Python есть встроенная функция reversed():</p>
10 <p>Вместо списка функция вернула объект итератор. Итераторы это особые объекты, представляющие собой абстракцию "поток данных". С понятием потока данных (или стримами "stream") вы будете также встречаться в других языках, и везде они используются для ленивых вычислений. Потоки особенно важны при работе с большими объемами данных или при обработке данных в режиме реального (потокового) времени. Потоки часто используются при чтении и записи файлов, при работе с видео- и аудиоданными, а также для работы со стримингами. Потоки позволяют обрабатывать элементы по запросу, а не загружать все данные сразу в память, что очень важно, так как данные могут быть потенциально бесконечными.</p>
10 <p>Вместо списка функция вернула объект итератор. Итераторы это особые объекты, представляющие собой абстракцию "поток данных". С понятием потока данных (или стримами "stream") вы будете также встречаться в других языках, и везде они используются для ленивых вычислений. Потоки особенно важны при работе с большими объемами данных или при обработке данных в режиме реального (потокового) времени. Потоки часто используются при чтении и записи файлов, при работе с видео- и аудиоданными, а также для работы со стримингами. Потоки позволяют обрабатывать элементы по запросу, а не загружать все данные сразу в память, что очень важно, так как данные могут быть потенциально бесконечными.</p>
11 <p>В примере выше reversed() не возвращает сразу новую перевернутую коллекцию, а создает итератор, который уже по запросу отдает по одному элементу с конца коллекции. Так можно в целом описать концепцию ленивых вычислений -<strong>не вычислять ничего, пока не нужно</strong>. Таким образом мы экономим вычислительные ресурсы, можем обрабатывать очень большие объемы данных (и даже "бесконечные"), а еще выстраивать цепочку вычислений и запускать ее по требованию.</p>
11 <p>В примере выше reversed() не возвращает сразу новую перевернутую коллекцию, а создает итератор, который уже по запросу отдает по одному элементу с конца коллекции. Так можно в целом описать концепцию ленивых вычислений -<strong>не вычислять ничего, пока не нужно</strong>. Таким образом мы экономим вычислительные ресурсы, можем обрабатывать очень большие объемы данных (и даже "бесконечные"), а еще выстраивать цепочку вычислений и запускать ее по требованию.</p>
12 <p>Получать элементы из итератора можно несколькими способами.</p>
12 <p>Получать элементы из итератора можно несколькими способами.</p>
13 <ul><li>Функцией next(), которая вызывает у итератора метод __next__(), а уже он извлекает из итератора следующий элемент. Если попытаться вызвать next() после последнего элемента, то функция сгенерирует исключение StopIteration:</li>
13 <ul><li>Функцией next(), которая вызывает у итератора метод __next__(), а уже он извлекает из итератора следующий элемент. Если попытаться вызвать next() после последнего элемента, то функция сгенерирует исключение StopIteration:</li>
14 </ul><ul><li>Итератор можно обойти в цикле. На самом деле, обход не только итератора, но и любой коллекции в цикле for .. in выглядит так: у коллекции запрашивается метод __iter__(), возвращающий итератор. Затем, на каждом шаге итерации вызывается метод __next__(). А когда сгенерируется исключение StopIteration, Python прекратит обход. То есть алгоритм в точности повторяет, то что мы видели выше, но автоматизирован.</li>
14 </ul><ul><li>Итератор можно обойти в цикле. На самом деле, обход не только итератора, но и любой коллекции в цикле for .. in выглядит так: у коллекции запрашивается метод __iter__(), возвращающий итератор. Затем, на каждом шаге итерации вызывается метод __next__(). А когда сгенерируется исключение StopIteration, Python прекратит обход. То есть алгоритм в точности повторяет, то что мы видели выше, но автоматизирован.</li>
15 </ul><ul><li>Также итератор можно конвертировать в составной тип данных типа списка или словаря, вызвав соответсвующую функцию list или dict. В таком случае, Python также обойдет весь итератор до конца, и создаст из него новую коллекцию.</li>
15 </ul><ul><li>Также итератор можно конвертировать в составной тип данных типа списка или словаря, вызвав соответсвующую функцию list или dict. В таком случае, Python также обойдет весь итератор до конца, и создаст из него новую коллекцию.</li>
16 </ul><p>Также Python позволяет получать объект итератора из коллекции явно, используя функцию iter():</p>
16 </ul><p>Также Python позволяет получать объект итератора из коллекции явно, используя функцию iter():</p>
17 <p>При работе с итераторами важно помнить, что по итератору можно двигаться лишь в одном направлении пока итератор не исчерпает себя. Также если мы прервем обработку и вернемся к итератору вновь, то обработка продолжится с места остановки.</p>
17 <p>При работе с итераторами важно помнить, что по итератору можно двигаться лишь в одном направлении пока итератор не исчерпает себя. Также если мы прервем обработку и вернемся к итератору вновь, то обработка продолжится с места остановки.</p>
18 <p>Еще одна популярная функция в Python, которая возвращает итератор - zip(). Функция zip() принимает неограниченное число коллекций (или любых других итерируемых источников) и последовательно возвращает кортежи из первых элементов, вторых, третьих и так далее, пока не закончится одна из коллекций.</p>
18 <p>Еще одна популярная функция в Python, которая возвращает итератор - zip(). Функция zip() принимает неограниченное число коллекций (или любых других итерируемых источников) и последовательно возвращает кортежи из первых элементов, вторых, третьих и так далее, пока не закончится одна из коллекций.</p>
19 <p>В примере выше, zip() принимает разные итерируемые источники: список, строку и итератор-поток. Затем выводит кортежи пока не закончится самый короткий из источников, в нашем случае итератор c.</p>
19 <p>В примере выше, zip() принимает разные итерируемые источники: список, строку и итератор-поток. Затем выводит кортежи пока не закончится самый короткий из источников, в нашем случае итератор c.</p>
20 <h2>Генераторы</h2>
20 <h2>Генераторы</h2>
21 <p>Помимо встроенных функций как reversed(), возвращающих итераторы-потоки, в Python есть инструменты для создания своих потоков:</p>
21 <p>Помимо встроенных функций как reversed(), возвращающих итераторы-потоки, в Python есть инструменты для создания своих потоков:</p>
22 <p>Подобные функции, ведут себя как итераторы и на каждом шаге итерации<strong>генерируют</strong>новое значение. Для них есть специальное название -<strong>генераторы</strong>.</p>
22 <p>Подобные функции, ведут себя как итераторы и на каждом шаге итерации<strong>генерируют</strong>новое значение. Для них есть специальное название -<strong>генераторы</strong>.</p>
23 <p>Определение функции выше похоже на привычное нам за исключением нового слова yield, которое используется вместо return. Основное отличие генераторных функций, что после исполнения yield, функция не завершается, а приостанавливается до нового шага итерации. Функция отдаст значение, указанное после yield и возобновит свое выполнение.</p>
23 <p>Определение функции выше похоже на привычное нам за исключением нового слова yield, которое используется вместо return. Основное отличие генераторных функций, что после исполнения yield, функция не завершается, а приостанавливается до нового шага итерации. Функция отдаст значение, указанное после yield и возобновит свое выполнение.</p>
24 <p>С помощью генераторов можно реализовывать собственные потоковые данные или даже реализовывать бесконечные потоки данных:</p>
24 <p>С помощью генераторов можно реализовывать собственные потоковые данные или даже реализовывать бесконечные потоки данных:</p>
25 <h2>Выводы</h2>
25 <h2>Выводы</h2>
26 <p>В этом уроке мы узнали, что такое Lazy Evaluation. Это стратегия вычисления, согласно которой вычисления следует откладывать до тех пор, пока не понадобится их результат.</p>
26 <p>В этом уроке мы узнали, что такое Lazy Evaluation. Это стратегия вычисления, согласно которой вычисления следует откладывать до тех пор, пока не понадобится их результат.</p>
27 <p>Также мы узнали, как в Python реализуются ленивые вычисления с помощью итераторов и генераторов. Узнали, что функции для обработки коллекций часто возвращают итераторы, потоки данных, для эффективного использования памяти. Также мы научились использовать итераторы и создавать собственные функции, генерирующие потоки данных. Ленивые вычисления и потоковая обработка - это ключевые инструменты в работе с большими данными.</p>
27 <p>Также мы узнали, как в Python реализуются ленивые вычисления с помощью итераторов и генераторов. Узнали, что функции для обработки коллекций часто возвращают итераторы, потоки данных, для эффективного использования памяти. Также мы научились использовать итераторы и создавать собственные функции, генерирующие потоки данных. Ленивые вычисления и потоковая обработка - это ключевые инструменты в работе с большими данными.</p>