Я говорил сегодня с моим коллегой о веб-фреймворках Python и наших впечатлениях о них. Я сказал ему, что думаю, что у Flask глобальный запрос плохо пахнет и это анти-паттерн.
В документах говорят о контексте запроса:
Напротив, во время обработки запроса существует пара других правил:
- пока запрос активен, локальные объекты контекста (flask.request и другие) указывают на текущий запрос.
- любой код может получить доступ к этим объектам в любое время.
Я думаю, что понимаю идею этого дизайнерского решения - сделать приложение проще. Это просто компромисс, как в случае с Thread Locals :
Да, обычно не такая яркая идея использовать локальные потоки. Они создают проблемы для серверов, которые не основаны на концепции потоков и затрудняют обслуживание больших приложений. Однако Flask просто не предназначен для больших приложений или асинхронных серверов. Flask хочет быстро и легко написать традиционное веб-приложение.
Является ли исправление глобального объекта с информацией о текущем запросе антипаттерном?
Я полагаю, что это так, потому что, по мнению статического анализатора кода, это глобальное состояние, хотя это не так. И я, как программист, не пойму, как это работает, не прочитав внимательно документы . И это имеет последствия на тестах .
Разве не рекомендуется передавать запрос в качестве аргумента представлениям? Я думаю, что это более читабельно, явно и легче для отладки. И избегает глобального состояния.
источник
Ответы:
Многие веб-фреймворки имеют такую же структуру: глобальный запрос. В некотором смысле, это правильно, потому что на самом деле существует только один запрос за раз.
Так есть ли смысл передавать запрос как параметр? Нет. Запрос - это запрос, а параметры - для передачи в разные вещи в разное время.
Реальная проблема возникает , как вы начинаете рассматривать более низкие уровни более крупного приложения. При глобальном запросе возникает соблазн написать код повсюду, который обращается к запросу глобально. Это очень плохо . Он создает связь между различными частями кода, затрудняет изменения и затрудняет тестирование.
Итак, мой ответ: сохранить глобальный запрос и жить с ним. Однако там, где отдельному модулю или функции не требуется полный запрос, передайте в качестве параметра только те данные, которые ему необходимы. Передайте в свои функции только реферер, или URL, или хвост команды, и все, что вам нужно. Это поможет сохранить код модульным, уменьшить связь и улучшить тестируемость.
Для крошечных программ это вряд ли имеет значение, но для более крупных это может стать настоящей спасательной программой.
источник
(Я собираюсь пойти смелым и сделать это ответом, хотя я мог бы получить некоторые отрицательные голоса.)
Колба представляет собой микрорамку; Вы выигрываете от простоты, отказываясь от излишеств. Хотя я согласен с вами, но знаю, что в одном магазине я использовал колбу + gunicorn, чтобы дать мне многопоточность, в которой я нуждался. Это сработало очень хорошо. Каждый экземпляр скрипта просто передавал один запрос (т. Е. Один поток), а gunicorn обрабатывал «веер» среди нескольких потоков. Это было здорово.
Таким образом, ощущаемая обратная сторона, которую вы чувствуете - что несколько потоков могут бороться за глобальное состояние - просто не проблема, потому что это один сценарий на поток.
(Вот где у меня могут возникнуть проблемы) Потоки и параллелизм просто различны в мире Python, и если вы придете к этому с настроением Java, трудно будет втиснуть это. Мой опыт заключался в том, что проблемы параллелизма, которые я принял для предоставленные в Java или прозрачно обрабатываемые контейнером приложения, намного ближе к поверхности в Python.
Мне было странно, что один поток обрабатывал один вызов моего скрипта, но после того, как я запустил несколько десятков одновременно на коробке, я почувствовал себя лучше.
источник
В Python у вас есть
print
команда (функция начиная с v3), которая печатает на стандартный вывод. Вы не указываете явно, что хотите печатать в STDOUT - это сделано для вас негласно за кулисами.Косвенно. В питоне. И ни у кого нет проблем с этим. Зачем?
print
является частью языка Python, и одним из требований программирования на Python является ... хорошо ... знание Python. И если вы знаете Python, вы знаете, что онprint
нацелен на STDOUT. Там нет сюрпризов.Python - как язык - может определить свое собственное соглашение и предположить, что программисты знают о них.
Фреймворки также пользуются этой привилегией - это одно из ключевых отличий между фреймворком и библиотекой. Вам не нужно изучать библиотеку, чтобы использовать ее - вам просто нужно найти ту часть API, которая вам нужна, и предположить, что она соответствует соглашениям языка (или фреймворка). Вот почему вы не видите рекрутеров, ищущих людей со знаниями в GSON или Apache Commons. Но вы видите, что рекрутеры ищут людей с опытом работы с JQuery или Ruby on Rails или ASP.NET MVC - потому что это фреймворки, которые определяют свои собственные соглашения, которые вы должны изучить и знать.
Flask, как фреймворк, может определять соглашение для хранения контекста в глобальном локальном потоке - и это никого не должно удивлять, так что это не анти-паттерн.
источник
sys.stdout
. Если вы измените это, печать отправится в другое место.>>
оператор или передаваяfile
аргументprint
функции в Python3. Таким образом,sys.stdout
это просто значение по умолчанию, которое может быть переопределено.