Размышления о Питоне
Я программирую на Питоне шесть лет. За это время назрели некоторые мысли насчет языка и его роли в ай-ти. Я решил, что следующим погружением на несколько лет будет что-то функциональное. Зафиксирую соображения, пока не утратил контекст.
Ниже – попытка обозначить слабые и сильные стороны Питона. Постараюсь, чтоб не было банальщины в духе “много библиотек и широкое комьюнити”. Все сказанное – исключительно личное мнение, которое не навязываю никому.
Итак, преимущества:
Питон – коммерчески успешный язык
Приятно осознавать, что Питон используют не только в академических и любительских кругах, но и в бизнесе. Компании доверяют ему деньги. Много фирм используют Питон – Гугл, Пейпал, Инстаграм, НАСА.
Питон создает рабочие места. Вакансий много, в том числе и в России. Питон – промышленный язык. Он стоит в одном ряду с Плюсами и Джавой по востребованности. Разработчик на Питоне имеет шанс попасть в настоящую разработку продукта. Это не суррогат местного потребления вроде 1С.
Питон – очень легкий язык
Вместе с тем, Питон чрезвычайно легко освоить. Основы учатся за неделю. Еще неделю займут пакеты и подготовка окружения. В итоге, меньше чем за месяц можно добиться места в проекте.
В Питоне мало сложных тем. Так я называю разелы языка, на изучении которых останавливаешься отдельно. В Лиспе один сложный момент – макросы. В Скале больше – трейты, импликты, составные объекты. В Питоне два – декораторы и метаклассы. В повседневной работе метаклассы не нужны, пожтому остатется только одна сложность. Разобравшись с декораторами, вы не встретите в языке других препятствий.
Питон сильно приблизил програмирование к людям
Я ни разу не видел, чтобы этот пункт кем-то упоминался. Питон стал языком, с которым любой инженер, ученый или технарь без навыков программирования могут решить задачи промышленного уровня. Питон – инструмент решения проблем.
Появились специальные проекты и книги, например, Python For Engineers, A Primer on Scientific Programming with Python и другие. На работе я видел скрипты на Питоне, написанные людьми, у которых все знание программирования сводилось к школьной программе. Но скрипты работали, автоматизировали труд, а значит, экономили время и деньги.
С Питоном управлять машиной стало проще. На каждую задачу найдется копипаста со Стек-Оверфлоу. Что бы ни загуглили – разбить строку, построить график, перемножить матрицы – в первых трех ссылках выдачи обязательно будет решение.
Конечно, подобный стиль простителен только не-программистам, когда важно получить результат, а не надежный поддерживаемый код.
Питон – легкий способ попасть в промышленную разработку
Напоминает тезис о том, как попасть в шоу-бизнес через постель. Если вы занимаетесь чем-то около-айтишным, например, администрированием, сетями, поддержкой, 1С или старыми языками вроде Дельфи, то Питон – счастливый билет. Из пунктов выше мы выяснили, это что легкий язык промышленного уровня. Возможно, он станет той подножкой уходящего поезда, на которую успеете вскочить, прежде чем расхочется что-то менять и превозмогать.
Абзацем выше я фактически рассказал свою историю. До знакомства с Питоном я занимался сайтами на CMS, Дельфями и 1С. Конечно, и с этим можно найти работу. Однако, именно за счет Питона я продвинулся на старой работе, потом переехал в другой город за 6000 км и попал в Датаарт. Позже нашел удаленку в Европе.
Питон поддерживает все парадигмы программирования
Питон удивидельно гибок. Его дизайн и синтаксис в равной степени поддерживают большинство парадигм. Стандартное ООП, императивный подход, процедурно-модульный, функциональный.
Каждая парадигма реализована в неполной манере. Так, в ООП нет приватных переменных и интерфейсов. Двойное подчеркивание – хак и обходится на раз. Интерфейсы пишут миксинами, но точное следование интерфейсу отследить невозможно.
Для полноценного ФП не хватает полноценных лямбд и неизменяемых коллекций. В
тройке функцию reduce
запрятали в недра стандартной библиотеки.
Ленивые вычисления, декораторы и перегрузка операторов открывают пространство для интересных маневров. Питон мимикрирует под самые разные языки, например:
-
Fake Lisp – псевдо-Лисп, забавная попытка писать питонячий код S-выражениями.
-
Hask – закос под синтаксис Хаскела. Питонщикам очень полезно посмотреть, на какие ухищрения пошел автор, чтобы добиться столь точного сходства.
-
fn.py – функциональные ништяки из Скалы. Аналогично, очень интересно взглянуть, что под капотом.
Резонный вопрос, зачем такая гибкость? Мой ответ – чтобы оттачивать паттерны и подходы, расширять кругозор, принимать на вооружение лучшие практики из других языков и платформ.
Например, одна функция из Кложи, портированная в Питон, сэкономит много строк кода и избавит от досадных багов. Или, встретив новый паттерн, я пробую реализовать его в Питоне, чтобы оценить, насколько он уживается в рамках большого проекта.
Закончим с преимуществами. Питон не идеален. Вижу следующие недостатки:
Мелкие огрехи с синтаксисом
У Питона лаконичный синтаксис без лишних скобок, точек с запятой и прочей мишуры, нужной машине, а не человеку. Все же, остаются способы отстрелить ногу и проверсти час в дебаге, не понимая в чем дело.
Формирование кортежа. Может, кто-то не знает, что круглые скобки вокруг кортежа носят символический характер. На самом деле он определяется запятой. Возникает проблема кортежа с одним элементом:
foo = 1, 2 # it's tuple
bar = 1, # it's tuple
baz = 1 # it's int!
Забыл запятую – получил не кортеж, а число. Оставил на хвосте запятую – не число, а кортеж. Не страшно, код упадет из-за разных типов. Начнется боль, когда кортеж строк. Строка и кортеж поддаются общим операциям: итерации, доступу по индексу, срезу. Код отрабатывает без падений, но выдает неверный результат. Из-за одной запятой.
Следующий пример. Две строки подряд без запятой сливаются в одну. Это значит, кортеж
statuses = (
'success',
'error'
'timeout',
'denied',
)
вырождается в
('success', 'errortimeout', 'denied')
потому что нет запятой после 'error'
. Проверка 'error' in statuses
вернет
False
, что есть прямое нарушение бизнес-логики.
Код на Питоне очень хрупкий и нуждается в обильном покрытии тестами. На шестом году работы с ним я до сих пор не уверен, правильно ли отработает тот или иной участок кода без теста.
Главенство ООП
Хоть Питон и поддерживает множество парадигм, основной остается ООП. Типичный фреймворк или библиотека – это набор классов, которые хранят состояние и меняют друг друга.
Вы когда-нибудь дебажили Джанго? Я да. Это был кастомный бекенд авторизации. Дебаг длился больше часа и напоминал БСДМ-сессию.
Объекты Request
, Response
, User
, Session
устраивают свальный
грех. Устанавливают ссылки друга несколько раз. Лезут в кэш непонятно
зачем.
Очень странные требования к бекенду авторизации. Метод .get_user()
отдает
объект пользователя. Потом этот пользователь где-то теряется, на него не
остается ссылки. Система запрашивает метод .get_user_by_id()
. Я ведь уже отдал
пользователя, дубина! Значит, нужно или снова лезть в базу или сеть, либо
хранить в классе словарик, что не тред-сейф.
Почему-то в Кложе с ее неизменяемыми коллекциями мне ни разу не приходилось лазить в сессию, реквест или респонс задним числом и что-то там править. Изменения в коллекции прокидываются только вперед.
Я не призываю программировать в сплошном ФП-стиле. Признаться, все эти статьи в духе “Программирование на Питоне в функциональном стиле” выглядят жалко. Совершенно за уши притянуты редьюсы и трехэтажные лямбды. Такой код не уживается в рамках проекта и будет выпилен, даже если его удастся как-то протащить.
Это наносит урон функциональному программированию. Распространяется заблуждение, что ФП – это мапы и лямбды.
В Питон было бы неплохо добавить что-то, что поощряло отказ от состояния. Например, неизменяемый словарь, больше функций для работы с коллекциями.
Впрочем, это был бы уже совсем другой язык.
Низкая скорость
Еще год назад говорил, что это не недостаток вовсе. Память дешевая, хостинг недорогой и прочие отмазки. Сегодня считаю такой ответ уделом дилетанта.
Скорость исполнения важна. Представьте, весь ваш софт на компе написан на Питоне. Он бы работал раз в 20-30 медленней, об играх и фотошопах пришлось забыть. Это не просто шаг назад, а откат на несколько поколений.
Недавно мне нужно было парсить лог Nginx, Гугл выдал утилиту ngxtop. Я не посмотрел, на чем она написана, поставил из пакетов. Лог в несколько гигабайт она обрабатывала час. Оказался Питон. Утилита на Си распарсила за 5 минут. Неверный выбор стоил потери времени.
Питон долго брал скоростью разработки. Да, работает медленней, зато выкатим
раньше, чем конкурент на Джаве. И вот появляются языки, которые совмещают
скорость кода и скорость разработки. Если писать на X
и Y
по времени
примерно одинаково, а Y
исполняется быстрей в 5 раз, зачем брать X
?
Насчет дополнительного железа. Говорить, что поставить вторую ноду – плевое дело может лишь тот, кто пишет код и не притрагивается к деплою. Несколько нод – это распределенная система. Нужен балансировщик, разделение логов, проблемы синхронизации, согласованные обновления.
В моем личном проекте долго жил Питон, нагрузка постоянно росла. Сервер задыхался, я не успевал поднимать тарифный план. Затем плюнул и переписал на Кложе. Не забуду это чувство, когда график CPU упал с 80 до 20 процентов.
ГИЛ
На упрек в адрес ГИЛа отвечают в духе “он вам не нужен”, “используй процессы”. Так говорил и я до тех пор, пока не познал, как работает многопоточность в функциональных языках.
Мы запускаем веб-приложение на Питоне под uWSGI так. Стартует мастер-процесс. Он управляет воркерами – процессами, в каждом из которых веб-приложение. Единовременно запущены 16 Джанг, каждая из которых отвечает, когда другая занята.
Мастер-процесс следит, чтобы все были равны. Убивает тех, кто не отвечает, выжрал слишком памяти или перетрудился – выработал лимит запросов.
Я считаю этот способ уродливым. Во-первых, налицо недоверие к технологии и ее нестабильное поведение. При длительной работе процессы текут, даже мастер-процесс. Это значит, систему нужно перезапускать.
Распараллеливание на процессах лишает общего доступа к памяти, вынуждая использовать суррогаты вроде Memcache или Redis, в то время как самый эффективный кеш – общая память.
Мастер-процессы вроде uWSGI и Green Unicorn – дополнительная прокладка в цепи, по которой проходит запрос. Лишний I/O, точка логирования и падения.
Наконец, с ГИЛом нельзя ничего распараллелить, разве что запросы в сеть. Функциональные языки лишены этих недостатоков. Неизменяемость коллекций в Кложе, система каналов в Гоу позволяют рулить многопоточностью без страха отстрелить ногу. Это выкашивает целый пласт инфраструктуры: костыли в виде очередей, воркеров и крон-скриптов. И дополнительные системы, чтобы все это поддерживать.
Трудности распространения
Приложение, написанное на Питоне, трудно распространять. Маленький скриптик требует интерпретатор определенной версии, виртуальное окружение с кучей библиотек. На вопрос, как перенести окружение на машину пользователя, нет точного ответа.
Несколько лет назад я пробовал различные упаковщики: Py2Exe
, PyInstaller
,
CxFreeze
. Собрать без ошибок приложение под Винду смог только
последний. Сделал это очень хорошо: выдал *.msi-инсталлятор, зарегистрировал
системную службу. Но времени на сборку и чтение доков ушло немало. Почему
разработчики Питона не озаботятся тем, чтобы включить в коробку систему
распространения конечного продукта?
Чтобы написал скрипт, запустил сборку и получил архив с исполняемым файлом. Почему функциональные языки это умеют, а Питон – нет?
Кложа выдает uberjar. Собираю его на Маке, загружаю на хостинг, где кроме Джавы ничего нет – работает без проблем. Хаскель компилируется в бинарь. Ракет, Раст – тоже. Коммон Лисп, которому тридцать лет, Карл, делает дамп Лисп-машины в бинарный файл!
Фактически, чтобы запустить веб-приложение на Питоне, нужно иметь примерно 10.000 *.py-файлов. Если не будет одного, система не заведется. Изолировать это многообразие можно Докером, но здесь мы кривим душой.
Листая документацию к третьему Питону, обнаружил занятный модуль zipapp. В первую минуту подумал, что напрасно упрекал язык, дело сдвинулось с мертвой точки. Оказалось, модуль не поддерживает виртуальное окружение и сишные библиотеки. Собрать простое приложение с драйвером Постгреса я не смог.
Заключение
Такие получились пункты. Надеюсь, никого не обидел критикой в адрес языка.
Ничуть не жалею, что потратил на Питон столько лет. Пусть следующий язык внесет в мою жизнь не меньший вклад.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter
Timur Malikin, 29th May 2016, link
Спасибо за статью, очень познавательно! Нашел очепятку - "Может, кто-то нА знает, что круглые скобки".
Ivan Grishaev, 29th May 2016, link , parent
Благодарю, поправил.
Nick Lesnykh, 1st Jun 2016, link
>> Недавно мне нужно было парсить лог Nginx, Гугл выдал утилиту ngxtop. Я не посмотрел, на чем она написана, поставил из пакетов. Лог в несколько гигабайт она обрабатывала час. Оказался Питон. Утилита на Си распарсила за 5 минут. Неверный выбор стоил потери времени.
Несомненно, есть в питоне минусы. О них нужно знать как при разработке, так и при выборе софта, который ты используешь. Но это утверждение можно применить к абсолютно любому языку программирования. Налицо проблема выбора тобой инструмента, а разработчиком инструмента - языка программирования.
Nick Lesnykh, 1st Jun 2016, link
>> Наконец, с ГИЛом нельзя ничего распараллелить, разве что запросы в сеть.
Как часто ты сталкивался с ограничениями GIL в веб-проектах? Веб, по сути, это бОльшая часть промышленного питона. Окей, предположим, что с архитектурой приложения все окей и тебе действительно надо что-то посчитать, или обработать изображение, или что-то еще перед отправкой ответа с сервера. В чем проблема вынести это в C extension? Или добавить микросервис, написанный на чем-то сверхбыстром? Вангую, что это будет быстрее и дешевле, чем разогнать команду питонщиков и самому переписывать на эрланге.
Nick Lesnykh, 1st Jun 2016, link
>> Распараллеливание на процессах лишает общего доступа к памяти, вынуждая использовать суррогаты вроде Memcache или Redis, в то время как самый эффективный кеш – общая память.
Как связаны существование Memcache и Redis и недостатки питона? Общая память двух потоков в операционной системе и системы распределенного кеширования? Для процессов в операционной системе (если не устраивают потоки) есть куча IPC техник. А Memcache и Redis используются совсем для другого.
Nick Lesnykh, 1st Jun 2016, link
>> Фактически, чтобы запустить веб-приложение на Питоне, нужно иметь примерно 10.000 *.py-файлов. Если не будет одного, система не заведется.
pip, виртуальные окружения, приватные pypi репозитории - одна из самых удобных вещей, которые можно встретить. На самом деле, это очень круто, когда можно установить все зависимости приложения, в том числе собираемые из исходников, в одну команду. Как только начинаешь собирать средней руки проект на C++ с зависимостями, часть которых линкуется статически, а другая - динамически, то тут начинается ад.
Tim, 2nd Jun 2016, link
Иван, что называется "Критикуешь предлагай" . Я не программист, но хочется в своем арсенале иметь хоть маломальский инструмент программирования. Мне этот инструмент приходилось использовать пару раз, и питон вроде как подходит. Но к примеру отсутствие компилятора, очень усложняет жизни дилетанту. Да я использовал pyinstaller, но сколько времени да и размер..
Прошу вашего совета, может быть есть что-то для профанов типа меня. Чтоб не сложно, кросплотформенно, возможность GUI и перспективно. Я понимаю что для каждого случая свой инструмент, но мне как не программисту изучать кучу языков...
Ivan Grishaev, 2nd Jun 2016, link , parent
Питон при всех недостатках -- хороший инструмент, владение им однозначно будет плюсом, особенно для начинающего. В перспективе посмотрите на Go, Rust, Racket.
Ivan Grishaev, 2nd Jun 2016, link , parent
Не утешает.
Ivan Grishaev, 2nd Jun 2016, link , parent
Я бы хотел как в Go, Rust или Racket -- на выхлопе бинарь со всем рантаймом на борту.
Ivan Grishaev, 2nd Jun 2016, link , parent
Да, хотелось бы кеширования в памяти в рамках нескольких тредов, а не процессов. Мемкеш и Редис -- это лишние походы в сеть и затраты на (де)сереализацию. Под большой нагрузкой оба инструмента ведут себя не так гладко. У нас же был ишью с кешем, помнишь?
Ivan Grishaev, 2nd Jun 2016, link , parent
Совсем недавно столкнулся. Си-экстеншены и микросервисы -- это усложнение и проблема.
Твой аргумент сводится к тому, что "этого нет, потому что не нужно". А бывает, нужно. Посмотри, как используют футуры и деферы в Скале и Кложе. Когда есть хорошие средства для параллельных вычислений, архитектура совсем по-другому строится.
Test, 26th Jun 2016, link
>>Еще год назад говорил, что это не недостаток вовсе.
Надеюсь с этим своим "мнением" не завернули на собесах(тех которых проводили) тех кто думал иначе ;)
А вообще поздравляю, вы из фанатика становитесь специалистом, понимающим что у всего есть своя цена и целесообразность ;)
Вася В, 14th Sep 2019, link , parent
если вы не программист, то вообще не суйтесь в разработку. дилетанты в разработке, это как собаке пятая нога, вроде должна помогать, но наоборот.
а если вы программист, то изучить новый ЯП не должно составить труда.
а так, вы верно заметили, каждой проблеме свой инструмент.