Выступление на Krasnodar Dev Days 2 о Python

Nov 2, 2017 10:40 · 1698 words · 8 minute read доклады

слайды

Всем привет! Меня зовут Тыщенко Виктор, я backend team-lead в компании 3d4medical. Вижу, тут собралось много людей, любящих решать задачи и интересующихся чем-то новым. У каждого из нас есть свои способы, свои проверенные инструменты и, в конце концов, любимые языки программирования. Я же хочу рассказать о своём, который помогает сосредоточиться на задаче, а не заставляет бороться с компилятором и вспоминать какие-то низкоуровневые конструкции.

Python

Что за зверь? Первая его версия вышла более 20 лет назад, причём написал его человек, получивший образование именно в сфере разработки языков программирования. Это не могло не сказаться на архитектуре - она достаточно логична и расширяема, что не предвещает какой-либо поломки обратной совместимости. Процесс разработки полностью стандартизован и описан в так называемых PEP. То есть сначала описывается некоторая функциональность, обсуждается, исправляется, и лишь потом реализовывается в языке. Многие скажут, что слишком много бюрократии, зато в итоге получается отличная документация, в которой описано не только что именно сделано, но и почему или для чего. За деталями реализаций смотрите уже исходники. Самые известные PEP8 и PEP20.

PEP

В PEP 20 приведены неформальные правила разработки, так называемый Дзен Python. “Явное лучше неявного”, “должен быть оди и желательно только один очевидный способ сделать это”. На самом деле я бы не сказал, что они применимы только для python, это некая философия программирования. Бывало, кидаешь pull request, а тебе так “увидев двойственность, отбрось желание угадать” - и сразу понятно где именно баг и как надо переделать. Или “читаемость имеет значение”, и ты уходишь переписывать так, чтобы глаз не спотыкался на синтаксических конструкциях.

PEP8. В нём описан стиль кодирования. Любой python-разработчик читает чужой код как свой. Больше нет споров ставить ли пробел после запятой или табы vs пробелы. Этот стандарт обязателен для соблюдения при работе в команде, но тем не менее компилятор не будет ругаться в случае его нарушения. На слайде лишь маленькая часть, но я настоятельно советую ознакомиться с ним целиком. Он довольно интересен и местами даже философичен. Например, там есть указание, когда стандарт может не применяться - я не стал переводить цитату.

Что очень важно - python поставляется с батарейками. Его стандартная библиотека очень обширна: тут есть и работа с аудио, и с архивами, комплексными числами, json, http и тому подобное. На примерах со слайда можно убедиться насколько проста работа с этим языком. Отформатировать дату - легко, поднять HTTP сервер - одной командой, выгрузить что-то в csv или sql - да пожалуйста! И что мне ещё нравится - ни одной лишней конструкции, всё очень лаконично.

Собственно, это ещё один плюс языка - чтобы выразить свою мысль не надо растекаться по древу и создавать структуры, выделять память, открывать ридеры от стрима, а потом ещё не забыть всё это дело освободить. Пожалуйста, избавьте меня от этого - мне всего лишь нужно прочитать первую строчку файла, дайте сосредоточиться на задаче. Так что благодаря высокой ёмкости и лаконичности языка, а также огромному репозиторию пакетов, программы на python занимают минимум строк и пишутся за минимальное время. В некоторых книгах не сразу даже понятно - то ли это код на python, то ли псевдокод.

Парадигмы

Python изначально разрабатывался как универсальный язык программирования, так что он поддерживает множество парадигм. Здесь есть и всем привычные классы, и лямбда-функции с map/reduce, и декораторы, и возможность легко создавать свой DSL, которых на самом деле полно. Одних ORM популярных штуки 3. Также я видел модули, написанные целиком в функциональном стиле, или пакеты, одно лишь подключение которых меняет поведение вашей программы. А всё благодаря отличной интроспекции.

Вы можете посмотреть список слотов объекта, изменить их значения, добавить новых. Например, вы можете написать декоратор deprecated, который модифицирует строку документации, добавляя туда предупреждение, что функциональность устарела. Кстати, JetBrains в своём дебаггере пошли ещё дальше - они модифицируют байт-код функции ещё до её выполнения. Но это тема уже отдельного доклада.

Область применения

Итак, где же он используется? Здесь лишь небольшой список продуктов, которые активно крутятся в продакш. Да, это высоконагруженные проекты, которыми мы пользуемся каждый день. Я специально оставил пустое место для вашего. Большинство из них вырастало из небольших прототипов, сделанных за пару месяцев. И ведь это очень удобно - сделать прототип, а потом точечно наводить оптимизацию.

Я это прочувствовал на собственном примере, когда создавал свою игрушку GeoPuzzle. Само ядро было написано недели за 2 по вечерам после работы, потом лишь упрощал админку и оптимизировал работу: что-то вынес в кеш, что-то в хранимку Postgres, поменял формат данных, подключил React/Redux. В итоге могу загружать прям оригинальные полигоны по 100 Мб с OSM, а информацию для инфобокса тянуть с Википедии. Так что подключение новой страны или района занимает минут 20.

Если же говорить о сферах применения, то:

  • он нашёл своё место в DevOps в виде популярных Ansible и Salt; если вам кажется странным синтаксис bash, попробуйте перейти на python;
  • на нём пишут GUI приложения - есть биндинги к Qt, GTK, Glade для всех популярных платформ
  • работа с данными, моделирование, построение графиков (numpy, pandas, matplotlib)
  • распознавание образов - OpenCV
  • парсинг сайтов - тот же Scrapy позволяет в декларативном стиле описывать что именно и с каких страниц мы должны собирать, а также модифицировать эти данные с помощью pipeline'ов ещё до сохранения на диск
  • библиотек для написания ботов просто валом, а уж руководств так вообще несчесть
  • ну и конечно же web-фреймворки: от простейших bottle и flask, до монстров типа django и pyramid. Кстати, на горизонте появилась ещё один: aiohttp.

Конкуррентность

В Python 3.5 наконец-то появилась нормальная аннотация для async/await, что послужило толчком к написанию всяких асинхронных библиотек к сторонним сервисам на базе asyncio и event loop. Уже готовы библиотеки для работы с postgres: aiopg и asyncpg; redis - aioredis; http server - aiohttp, sanic, - что ещё для работы нужно? :) Ниже я привэл пару примеров, чтобы показать, что это совсем не сложно, и код получается понятным.

На самом деле asyncio - очень важная часть современного python, можно сказать, что это аналог горутин. По сути вы запускаете свой менеджер процессов внутри одного из потока интерпретатора. Это существенно снижает накладные расходы на переключение между задачами. Справа приведён код для примера, что очень важно - есть возможность писать асинхронный код как синхронный.

Но первоначальная реализация была так скажем медленной. Встречайте uvloop, все мы любим бенчмарки, померяться циферками. На верхнем графике кол-во обработаных запросов за 30 секунд с concurrency 300. Как видите, асинхронность в python вполне может потягаться с реализациями на Go или Node.js. На нижнем графике скорость чтения строк из postgres для разных библиотек. Надо всё-таки заметить, что авторы графиков здесь всё-таки немного лукавят - и httptools, и asyncpg написаны не на стандартной реализации CPython, а на Cython - код которого надо транспайлить в C, а потом компилировать gcc. Хоть это и звучит страшно, но ставится всё той же командой pip install asyncpg. Так что это не мешает использовать их в вашей программе.

Оптимизация

И тут часто задают вопрос: Как такое может быть? Python же очень медленный! Выбросьте этот миф вместе с кодом на python 2.7. Как правило, вы будете упираться в производительность сети, но уж никак не CPU. В этой статье автор подкрепляет свои слова кучей исследований. Но даже если вам уже мало скорости работы виртуальной машины python, то можете реализовать узкое место на каком-нибудь низкоуровневом языке. Кстати, все узкие места давно заоптимизированы и переписаны на C: библиотеки для работы с XML, графикой или БД - их C-часть либо идёт в pip файле, либо ставится через apt-get. Благодаря продуманной системе биндингов, вы можете переписать отдельные места хоть на Rust, оставив логику на более высоком уровне. Так, например, делает EVE Online, которая целиком написана на Python, с оптимизацией узких мест кодом на Cython. Кстати, на тему игр - во многих из них на python пишутся некие высокоуровневые сценарии, которые в свою очередь дёргают методы движка.

Да, на самом деле Python это не только основная реализация CPython, но также и набор соглашений тех самых PEPов, основываясь на которых, было создано несколько интерпретаторов для других платформ. Например, Jython, который работает поверх JVM, или IronPython поверх .Net. Проект Grumpy, который затеял Google для конвертации Python кода в Go. Так что Python может быть как интерпретируемым, так и компилируемым - всё зависит от конкретной реализации.

Код на Cython вообще транслируется в C, который потом компилируется обычным gcc. Да-да, есть возможность писать низкоуровневый код так, чтобы он был понятным. На примере я хотел показать как он выглядит. Всё то же самое - классы, функции, методы. Скорость выполнения не уступает аналогичной на C, но вы можете импортировать его как обычный пакет в свой код на CPython. Даже более того, это считается стандартной практикой - тот же uvloop - обёртка на Cython над системной библиотекой libuv. Та же история и с lxml.

Будущее языка

О, да, статическая типизация! Как же мне её не хватало. Когда в переменной вдруг оказывается список - начинаешь недоумевать, и идёшь по стеку в поисках той сволочи, которая вернула результат не в том виде. Ну да, тесты помогают, но много ли их пишется? Кстати, кто пишет тесты? А у кого coverage больше хотя бы 95%? Вот вам ещё один способ проверки, что код работает как вы задумали - в 3.5 появилась возможность указывать типы. Не будет больше ошибок типа undefined is not a function. Так что все сложные и критичные вещи типа биллинга я стараюсь писать с вот такими вот подсказками. Правда, пока эта проверка только на этапе написания кода, но в дальнейшем с её помощью можно существенно оптимизировать расход ресурсов. Вы ж сами рассказываете интерпретатору где какие типы использовать, грех этим не васпользоваться. Так что проставляйте типы, это пригодится.

Кстати, о новых фичах. Каждый новый релиз всё вкуснее и интереснее. В недавнем 3.6 добавили ещё один способ форматирования строк. Думаю, многим придётся по вкусу. Позаботились о числовых константах - теперь разряды можно разбивать символами подчёркивания для наглядности. В каком ещё языке столько внимания уделяют читаемости? API asyncio наконец-то стабилизировался и проник в list comprehensioin, а оптимизация некоторых его классов дала прирост производительности аж в 30%. И, что не может не радовать - оптимизация среды выполнения. Если кому интересно, после доклада могу рассказать как спустя 10 лет разработчики нашли способ оптимизировать рантайм аж на 10%.

Заключение

На самом деле тема Python весьма обширна. Сложно уложиться в 30 минут. Есть много интересных тем: GIL, создание desktop-приложений или ботов, работа с различными библиотеками и фреймворками. Так что у меня к вам просьба: если тема интересна, отловите меня и поделитесь о чём ещё хотите услышать. Я обязательно передам эту информацию организаторам.

На этом всё, спасибо за внимание!