Это действительно можно реализовать через рекурсию, а можно реализовать через треды и очереди. А можно заинлайнить и оставить цикл снаружи, а можно... Да миллион вариантов. Человек старательно путает семантику кода и реализацию.
def inner():
for x in range(10000000):
yield x
gen = inner()
ещё раз, тут нет рекурсии нигде!!! Ни в одной строке кода не происходит повторного обращения к inner, она вызывается один раз - снаружи. Это не рекурсия! вход в функцию происходит ровно один раз, а вон внутри она уже ставится на паузу.
Вот выше приводились примеры реализации генератора через псевдоцикл и через рекурсию.
Не надо. Приводился пример генератора как отдельной сущности в языке и эмуляция генератора через рекурсию.
Если в языке есть отдельная сущность - внутри может использоваться обычный цикл, но это не обязатно, генератор может например выдавать фиксированное количество данных без цикла, но всё ещё лениво. Пауза в вывполнении не за счет изменения семантики цикла, она появляется за счет семантики yield. Идея в том, что если вам нужен генератор - сделайте генератор.
Собственно, идея почему отказались от goto - людям не нужны произвольные переходы , нужно решать несколько ситуаций и их можно выразить более безопасно и выразительно не теряя в функциональности. Попытка всё выразить через рекурсию так же плоха как попытка всё выразить через цикл.
Она не ложная, если представить что кроме потоков ОС есть логияеские потоки, которые синхронизированы. Просто я не хочу развивать эту терминологию, от нее в данном случае пользы мыло. Я привел этот аналог только потому что он вам будет понятен.
Нет, не надо использовать эти термины. Я мучаюсь тем, чтобы заставить вас использовать знакомые детали реализации и перейти к абстракции. Функция просто ставится на паузу. Всё. Никаких рекурсией, никаких замыканий нет. Есть функция, которую можно ставить на паузу и получать из нее данные по кусочку. А внутри функции такой же цикл как обычно, а может и не цикл.
Возможно такая аналогия будет проще. Представьте что у вас есть отдельный поток, который крутит бесконечный цикл. На каждом вызове yield он останавливается и ждёт пока основной поток съест данные. В реальности никакого потока не создаётся, но логически это очень близко
Тут нет косвенной рекурсии. Функция не запускается заново. Она просто приостанавливается и продолжается с того же места где остановилась. Как это реализовано внутри не важно.
Рекурсия равна вызову функции самой себя. На уровне исходного кода, не на уровне результата компилчции. В приведенном мной примере этого нет ни в каком виде. Это не рекурсия.
Нет там никакого рекурсивного вызова. Там просто сохраняется фрейм отдельно и дальше продолжается выполнение с того места где остановились.
В любом случае в статье речь именно про стиль написания кода, так то и рекурсия внутри превращается в цикл при оптимизации компилятором, но вы же это как-то игнорируете.
Генераторы - это закономерное расширение синтаксиса циклов, не ломающее стиль кода. В том время как рекурсия - альтернативная форма. Во что оно превращается внутри - да не важно вообще, наверняка там просто goto остаётся после всех возможных компиляций
В контексте, это возврат замыкания, которое содержит созадваемый неявно рекурсивный комбинатор, который так же неявно разворачиваетмч в цикл. Но нет, это даже не обязано быть рекурсивным комбинатором, что бы это ни значило, это просто объект у которого есть Стейт и метод next
Генерации бесконечной последовательности. Как рекурсия может генерировать бесконечную последовательность если у нее есть результат? Кажется дело не в рекурсии как таковой, а в типе результата
Соединения двух циклов. Как вы хотите соединить? Вдоль или поперек? Опять же, если у вас рекурсия, вы получили результат и всё. Так же как функция с циклом вернула результат. Дальше можно вызвать вторую или нет.
В коде Litestar было замечено кэширование плутов, что очень сильно влияет на бенчмарки и может совершенно не приносить пользы в реальных приложениях. Попробуйте динамический плуты вида /{id}, какой будет результат?
Что касается FastAPI - Фаст там не про скорость работы, а про скорость разработки, там есть куча мест, которые можно улучшать
На всякий случай дополню, что если используется ORM наоборот нет смысла делать двойное преобразование - пусть модели ORM и используются как сущности бизнес логики. Но это не должно означать что интнрфейс репозитория содержит какую-то информацию об устройстве таблиц и SQL как таковом, это всё ещё скрыто внутри.
Прошу прощения, что плохо выразил мысль. Под упрощением я имео ввиду не писать в сотый раз update или insert или не следить за тем чтобы имена таблиц после as не повторялись при джойнах на одну и ту же. Это не требует квалификации, это требует аккуратности. ORM же наоборот повышает требования к квалификации сотрудника - теперь ему мало знать SQL, надо ещё разбираться в дополнительной технологии.
А подскажите, как будет выглядеть бесконечный список единиц?
Это действительно можно реализовать через рекурсию, а можно реализовать через треды и очереди. А можно заинлайнить и оставить цикл снаружи, а можно... Да миллион вариантов. Человек старательно путает семантику кода и реализацию.
этот код - просто шорткат для
ещё раз, тут нет рекурсии нигде!!! Ни в одной строке кода не происходит повторного обращения к inner, она вызывается один раз - снаружи. Это не рекурсия! вход в функцию происходит ровно один раз, а вон внутри она уже ставится на паузу.
Не надо. Приводился пример генератора как отдельной сущности в языке и эмуляция генератора через рекурсию.
Если в языке есть отдельная сущность - внутри может использоваться обычный цикл, но это не обязатно, генератор может например выдавать фиксированное количество данных без цикла, но всё ещё лениво. Пауза в вывполнении не за счет изменения семантики цикла, она появляется за счет семантики yield. Идея в том, что если вам нужен генератор - сделайте генератор.
Собственно, идея почему отказались от goto - людям не нужны произвольные переходы , нужно решать несколько ситуаций и их можно выразить более безопасно и выразительно не теряя в функциональности. Попытка всё выразить через рекурсию так же плоха как попытка всё выразить через цикл.
Это генераторное выражение - альтернативный способ создать генератор. yield нету. цикл фактически есть, но он ленивый.
Она не ложная, если представить что кроме потоков ОС есть логияеские потоки, которые синхронизированы. Просто я не хочу развивать эту терминологию, от нее в данном случае пользы мыло. Я привел этот аналог только потому что он вам будет понятен.
Нет, не надо использовать эти термины. Я мучаюсь тем, чтобы заставить вас использовать знакомые детали реализации и перейти к абстракции. Функция просто ставится на паузу. Всё. Никаких рекурсией, никаких замыканий нет. Есть функция, которую можно ставить на паузу и получать из нее данные по кусочку. А внутри функции такой же цикл как обычно, а может и не цикл.
Возможно такая аналогия будет проще. Представьте что у вас есть отдельный поток, который крутит бесконечный цикл. На каждом вызове yield он останавливается и ждёт пока основной поток съест данные. В реальности никакого потока не создаётся, но логически это очень близко
Тут нет косвенной рекурсии. Функция не запускается заново. Она просто приостанавливается и продолжается с того же места где остановилась. Как это реализовано внутри не важно.
Рекурсия равна вызову функции самой себя. На уровне исходного кода, не на уровне результата компилчции. В приведенном мной примере этого нет ни в каком виде. Это не рекурсия.
Нет там никакого рекурсивного вызова. Там просто сохраняется фрейм отдельно и дальше продолжается выполнение с того места где остановились.
В любом случае в статье речь именно про стиль написания кода, так то и рекурсия внутри превращается в цикл при оптимизации компилятором, но вы же это как-то игнорируете.
Генераторы - это закономерное расширение синтаксиса циклов, не ломающее стиль кода. В том время как рекурсия - альтернативная форма. Во что оно превращается внутри - да не важно вообще, наверняка там просто goto остаётся после всех возможных компиляций
def gen(): while True: yield 1
for x in gen(): print(x)
У вас gen вызывается внутри gen. У меня - нет. Смотрите:
В контексте, это возврат замыкания, которое содержит созадваемый неявно рекурсивный комбинатор, который так же неявно разворачиваетмч в цикл. Но нет, это даже не обязано быть рекурсивным комбинатором, что бы это ни значило, это просто объект у которого есть Стейт и метод next
Нет, не является. В нем нет рекурсивного вызова на уровне языка. Генератор, это просто с внешним контролем перехода к следующему шагу. Смотрите:
Цикл, рекурсии нет, а генерирует бесконечную последовательность единиц.
А можно чуть подробнее раскрыть тему
Генерации бесконечной последовательности. Как рекурсия может генерировать бесконечную последовательность если у нее есть результат? Кажется дело не в рекурсии как таковой, а в типе результата
Соединения двух циклов. Как вы хотите соединить? Вдоль или поперек? Опять же, если у вас рекурсия, вы получили результат и всё. Так же как функция с циклом вернула результат. Дальше можно вызвать вторую или нет.
Так это не пример while, это for
В коде Litestar было замечено кэширование плутов, что очень сильно влияет на бенчмарки и может совершенно не приносить пользы в реальных приложениях. Попробуйте динамический плуты вида /{id}, какой будет результат?
Что касается FastAPI - Фаст там не про скорость работы, а про скорость разработки, там есть куча мест, которые можно улучшать
На всякий случай дополню, что если используется ORM наоборот нет смысла делать двойное преобразование - пусть модели ORM и используются как сущности бизнес логики. Но это не должно означать что интнрфейс репозитория содержит какую-то информацию об устройстве таблиц и SQL как таковом, это всё ещё скрыто внутри.
Прошу прощения, что плохо выразил мысль. Под упрощением я имео ввиду не писать в сотый раз update или insert или не следить за тем чтобы имена таблиц после as не повторялись при джойнах на одну и ту же. Это не требует квалификации, это требует аккуратности. ORM же наоборот повышает требования к квалификации сотрудника - теперь ему мало знать SQL, надо ещё разбираться в дополнительной технологии.