Я работаю консультантом в аналитической фирме, в основном в области Компьютерное зрение, и пишу сценарии Python, создание модулей - это как повседневная вещь. Я написал множество кодов, участвовал в нескольких конкурсах; черт возьми, я учу Python новичков внутри фирмы; но, и я не очень рад это признавать: «Я никогда не использовал ключевое слово « yield » в функции». До недавнего времени, когда я это делал 😃 (подробнее об этом позже)

Теперь немногие из тех, кто, возможно, прочитает эту статью, будут похожи на- «Какой идиот!», а некоторые из вас могут быть похожи на меня- «Зачем вообще его использовать?». Некоторые из них будут примерно такими: «Ммм, как и когда вообще его использовать?», и я не игнорирую тот факт, что меньшинство из нас может сказать - «Какой доход?»

ПРИМЕЧАНИЕ. Прежде чем мы продолжим, небольшое примечание: всякий раз, когда вы видите какой-либо отрывок в цитатах (например, тот, который вы сейчас читаете), это то, что я цитирую либо с веб-сайта, либо из человек. А чуть выше вы увидите что-то подчеркнутое и помеченное ЖИРНЫМ, что приведет вас к первоисточнику, где вы можете получить гораздо больше связанного содержания. Я не хочу отдавать должное чужой работе, поэтому проявлю должную осмотрительность 🙌.

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

Теперь, если вы поняли какой-либо намек из этого мема, он как бы намекает на то, для чего на самом деле полезен yield. Итак, вот ответ StackOverflow, который прекрасно резюмирует:

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

Возьми? Что ж, если бы кто-то показал мне тот же текст во время объяснения чего-либо, даже я бы в конечном итоге стоял с вытянутым лицом, не понимая, что означало это утверждение. Но приведенное выше утверждение в двух словах объясняет «доходность».

Давайте разберемся ...

В Python функция, как следует из названия, представляет собой блок кода, который запускается только при его вызове. Вы можете передавать данные, известные как параметры, в функцию. В результате функция может вернуть данные. Со мной еще? Хорошо!
Теперь замените ключевое слово return на yield. Вы получаете Генератор. (Как говорит парень из StatQuest - БАМ).

Постойте, а что такое Генератор?

Если функция содержит хотя бы один оператор yield (он может содержать другие операторы yield или return), она становится функцией-генератором. И yield, и return возвращают некоторое значение из функции.

Создать генератор на Python довольно просто. Это так же просто, как определить обычную функцию, но с помощью оператора yield вместо оператора return.

Разница в том, что в то время как оператор return полностью завершает функцию, оператор yield приостанавливает выполнение функции, сохраняя все ее состояния, а затем продолжает с этого момента последовательные вызовы.

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

Ладно, и что?

Итак, мой друг, это позволяет нам сделать наш код более эффективным с точки зрения памяти. Все еще не понимаете? Потерпи еще немного.

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

В этот момент вы можете снова сказать: «Хорошо, и что?». Ну, честно говоря, ничего. Эта вещь с памятью обычно не является большой проблемой. Фактически, у меня никогда не было такой проблемы, или никогда не было такого большого списка, который мне приходилось решать, чтобы использовать «yield». Пока я не столкнулся с проблемой, недавно спросил мой друг. Между прочим, она действительно милая и милая.

Постановка проблемы!

Дата 01–03–05 (1 марта 2005 г.) состоит из трех последовательных нечетных чисел. Это первый день в 21 веке с этой собственностью. Сколько всего дней с этой собственностью в 21 веке?

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

01–03–05
03–05–07
05–07–09
07–09–11
09–11–13

Я не мог придумать другого такого свидания. Я спросил, это ответ? Ее первый ответ был - я пытался уточнить у вас, я не знаю точного ответа. Что ж, облом. Но подождите, я знаю Python, почему бы просто не запрограммировать это?

Решение

Итак, я написал код ниже. Сейчас, когда я писал это, у меня было прозрение. Неужели мне действительно нужно составлять список всех дат 21 века, а затем перебирать их? Без прав? Все, что я хотел, - это назначить свидание, посмотреть, есть ли на нем три последовательных нечетных числа, и двигаться дальше. И тут мне в голову пришло «уступка». Я много раз учил новичков тому, что такое yield и что он делает, но сам никогда не использовал его. Я подумал, почему бы не попробовать это на этот раз, и сделал:

Таким образом, в приведенном выше коде, когда вы вызываете give_date(...), он создает генератор, который при вызове возвращает значение даты, а затем приостанавливает работу. Таким образом, я не храню все даты в списке, который потребляет много памяти. Для всех, кто интересуется, если я составлю список внутри функции и позволю ему сначала добавить все даты, а затем вернуть его, время выполнения кода будет почти таким же, но использование памяти генератором будет 120 байт , а в возвращенном списке будет 321104 байта!

Теперь, прежде чем кто-нибудь сойдет с ума, это всего лишь 0,3 МБ. Ну эффективность памяти помните? Здесь следует понимать, что, используя yield, мы создали генератор, который будет в 2675 раз меньше, чем список. Это значительная сумма. Для небольшого списка, содержащего все даты за 100 лет (на самом деле он не такой уж и маленький), это не имеет большого значения, но часто многие из нас имеют дело с гораздо большим объемом данных и хранят такое огромное количество данных в список совсем не идеален. И если вы не удалите какую-либо такую ​​временную переменную после ее использования, что я не думаю, что большинство из нас обычно делают, эта использованная память останется как есть. А если вы проделаете то же самое с помощью генератора, он перестанет существовать, как только его работа закончится. Да уж, не шучу. Я могу показать вам, взгляните:

Помните, что генератор - это итератор; то есть одноразового использования. Если вы хотите использовать его повторно, вам следует снова позвонить my_range(...). Если вам нужно использовать результат дважды / снова, вы должны сначала преобразовать результат в список и сохранить его в переменной likex = list(my_range(10)).

Теперь я знаю, как умный программист, многие из вас могут подумать, что это полная чушь! Не было даже необходимости в функции. Я знаю, знаю. То же самое можно сделать и так:

Опять же, с эффективным использованием памяти, не так ли? И я верю, что есть много других, более эффективных способов. В конце концов, всегда есть возможности для улучшения. Что ж, ребята, я привык писать код в форме функции, и на самом деле я отчасти рад, что не подумал писать код для этой проблемы таким образом, потому что я действительно увидел действительно хорошее использование « уступить »впервые в жизни.

И, эй, настоящий ответ на этот вопрос - а почему бы тебе не попробовать самостоятельно 😄. И если кто-то новичок во всем этом и кодировании, не стесняйтесь спрашивать меня в комментариях.

Я надеюсь, что эта статья или пост были интересны для всех, кто их прочитал. Моя искренняя благодарность всем, кто это сделал 😃. Я впервые пробую Medium, и, честно говоря, я просто пробую его по рекомендации коллеги и коллеги по среднему пользователю - Sreekiran. Также посмотрите его посты, они довольно хорошо осведомлены.

Еще раз спасибо, и если эта статья пойдет хорошо, я могу написать намного больше, возможно, в следующий раз о компьютерном зрении 👐.