Python https://digest.evrone.ru/ ru Cython, Flask и Quart https://digest.evrone.ru/20230809 <img src="/sites/default/files/styles/card_m/public/2023-08/vfdgnsb.png?itok=kVRYxRs5" width="960" height="540" alt="Cython, Flask и Quart" loading="lazy" typeof="Image" /> <br /> <p>Жаркий июль закончился, на дворе август. Нас порадовали мажорным релизом компилятора Cython, которого ждали несколько лет. Также мы решили узнать, в чём разница между двумя микрофреймворками Flask и Quart, а также нашли отличную статью про тонкости популярных конструкций, таких как with…contextmanager. Приятного чтения!</p> <h2>Вышел Cython 3.0</h2> <p>Этого события ждали несколько лет. Причина столь долгой работы над релизом в желании сохранить обратную совместимость с предыдущими версиями <a href="https://cython.org/">Cython</a>. Все актуальные на момент релиза версии CPython поддерживаются в Cython, включая даже экспериментальную 3.12. Python 2.6 на последней валькирии отправился в Вальхаллу, его поддержка была прекращена.</p> <p>Разработчикам теперь можно юзать линтеры и анализаторы кода, созданные для Python. Раньше такая роскошь была недоступна из-за особенностей синтаксиса Cython, так что привычный тулинг не работал.</p> <p>Ответ на это безобразие: <a href="https://cython.readthedocs.io/en/latest/src/tutorial/pure.html" rel=" noopener" target="_blank">Pure Python mode</a>, использующий только общепринятый синтаксис Python. Раньше часть кода, например функции для вызова внешних библиотек на C, в этом режиме не поддерживалась. Сейчас же весь код в режиме Pure Python можно «причёсывать» питонячьими линтерами и не испытывать при этом мучительных страданий.</p> <p>Ещё одним нововведением стала улучшенная поддержка NumPy. Cython давно позволял нативно писать функции внутри NumPy, но в некоторых случаях разработчики натыкались на разного рода ограничения. Теперь же можно, например, писать <a href="https://numpy.org/doc/stable/reference/ufuncs.html" rel=" noopener" target="_blank">универсальные функции NumPy</a> прямо в Cython и применять ко всему содержимому структуры данных.</p> <p>Как часто бывает в мажорных релизах, создатели позаботились и об архитектурных улучшениях. Так что кое-какие внутренние части Cython были переписаны. Это в будущем улучшит совместимость модулей расширения. Написанные для одной версии Python, они должны заработать и на будущих версиях, без регистрации и SMS повторной компиляции.</p> <p>Вот такие вот нововведения принес нам Cython 3.0. Обновление — хороший повод попробовать его в деле. За деталями советуем заглянуть в детальный <a href="https://cython.readthedocs.io/en/latest/src/changes.html" rel=" noopener" target="_blank">Changelog</a> релиза.</p> <h2>Микрофреймворк Quart</h2> <p>Любой Python-разработчик хотя бы раз в жизни слышал про микрофреймворк <a href="https://flask.palletsprojects.com/en/2.3.x/" rel=" noopener" target="_blank">Flask</a>. Он очень крут, но делает упор на простоту и консервативность. Если вам хочется тоже самое, что и Flask, но стильно, модно, молодёжно — рекомендуем обратить внимание на <a href="https://github.com/pallets/quart" rel=" noopener" target="_blank">Quart</a>. Это тоже микрофреймворк для веб-разработки, имеющий несколько важных отличий от Flask.</p> <p>В комплекте с Quart идёт <a href="https://asgi.readthedocs.io/en/latest/" rel=" noopener" target="_blank">ASGI</a> (асинхронный серверный интерфейс шлюза). Он поддерживается многими приложениями и платформами, так что с интеграцией не должно возникнуть проблем. Ещё одним способом взаимодействия будет старый добрый <a href="https://wsgi.readthedocs.io/en/latest/learn.html" rel=" noopener" target="_blank">WSGI</a> (интерфейс шлюза веб-сервера). Это один из штатных способов объединения нескольких приложений для обработки одного запроса. Реализация этого стандарта описана в <a href="https://peps.python.org/pep-3333/" rel=" noopener" target="_blank">PEP 3333</a>.</p> <p>Важное различие двух микрофреймворков в поддержке веб-сокетов. Flask по-умолчанию её не имеет, строго соблюдая концепцию микрофреймворков. Дескать, хочешь дополнительную фичу — будь добр найти и установить соответствующее расширение. Quart этот консервативный подход не разделяет, имея встроенную поддержку веб-сокетов, что делает его отличным выбором для разработки веб-приложений в реальном времени.</p> <p>Подведём итог: оба микрофреймворка облегчают жизнь разработчиков, а также делают веб-разработку на Python лёгкой и предсказуемой. Но там, где Flask пользуется исключительно проверенными методами и строго следит за соблюдением концепции микрофреймворка, Quart позволяет себе больше свободы. За счёт этого, его можно назвать более современным и продвинутым. </p> <p>Разумеется, оба имеют собственные уникальные фичи и ограничения. Но то, что есть альтернатива — приятно. </p> <h2>Тонкости популярных конструкций</h2> <p>О отличие от обычного, синтаксический сахар чаще всего полезен. И в Python его много. Привыкая к удобным конструкциям, мы перестаём задумываться о том, как они устроены внутри и какие задачи призваны решать. Чтобы лучше разобраться во всех этих моментах самому, а также помочь другим, Павел Корсаков из Beeline Cloud написал статью, в которой разобрал конструкцию <a href="https://www.geeksforgeeks.org/with-statement-in-python/" rel=" noopener" target="_blank">with</a>…<a href="https://www.pythonmorsels.com/what-is-a-context-manager/" rel=" noopener" target="_blank">contextmanager</a>.</p> <p>Присмотритесь повнимательнее к with…contextmanager: напоминает try…except. Если вы тоже поймали себя на этой мысли, то ваша интуиция вас не подвела — именно эта конструкция лежит в основе. Появилась она достаточно давно в таких языках как Ada, C++ и Java. Становится очевидно, что именно там её и подсмотрел Гвидо Ван Россум.</p> <p>Перед тем, как вникать в менеджер контекста, стоит задуматься — а что из себя представляет этот самый контекст? Под ним здесь подразумевается минимально возможный набор данных, позволяющих прервать выполнение кода и потом успешно продолжить с того же места. Ну а менеджер контекста — ничто иное, как синтаксический сахар, позволяющий удобно работать с подобными наборами данных.</p> <p>Теперь давайте посмотрим на историю with. Этот оператор изначально задумывался в качестве альтернативы try…finally. Чтобы объяснить, как это работает, советуем взглянуть на пример:</p> def foo(): try: a = 5 / 0 finally: print('finally 1') print('finally 2') <p>Как только интерпретатор дошёл до try, он запомнил контекст (текущий набор данных). Далее возможно два варианта развития событий:</p> <ol> <li aria-level="1">Если код внутри try не генерирует исключений, то интерпретатор запустит код в блоке finally и далее продолжит выполнение.</li> <li aria-level="1">Если код внутри try сгенерировал исключение, то после запуска finally программа завершится, т.к. имеется необработанная ошибка.</li> </ol> <p>Очевидно, что в примере выше события будут развиваться по второму варианту. В выводе будет «finally 1» и код ошибки. Вывода «finally 2» мы не увидим.  </p> <p>Но если мы то же самое реализуем с помощью менеджера контекста, поведение кода поменяется и станет удобнее. Задача конструкции with сделать так, чтобы гарантировать корректное завершение, например, закрытие файла, вне зависимости от того, чем закончится выполнение вложенного кода.</p> <p>За подробностями и примерами с with…contextmanager, рекомендуем заглянуть в оригинальный текст <a href="https://habr.com/ru/companies/beeline_cloud/articles/749580/" rel=" noopener" target="_blank">статьи</a> на Хабре. И если она вам понравилась, то не поленитесь поставить автору плюс в карму.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>29 ноября 2023</p> <p>Рады сообщить, что у нас запланирован осенний Python Meetup. Программа мероприятия формируется. Заявки на участие спикера <a href="https://docs.google.com/forms/d/e/1FAIpQLSedDbmB8mAtDb5_bKgUnmh8f6apOYXDsdvtXt1JPz7VoWqX2A/viewform?usp=sf_link" rel=" noopener" target="_blank">принимаются</a> до 10 ноября.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-4?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_8_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_8_2023" rel=" noopener" target="_blank">Подробнее</a></p> Wed, 09 Aug 2023 09:54:54 +0000 Evrone digest /20230809 Особое мнение https://digest.evrone.ru/20230705 <img src="/sites/default/files/styles/card_m/public/2023-07/dfgjjkglk%3B_0.png?itok=p9R5Yzjm" width="960" height="540" alt="Особое мнение" loading="lazy" typeof="Image" /> <br /> <p>Глобальные задачи и новые языки, мнения экспертов и полезные инструменты. Вы на частоте Evrone, здесь мы говорим о самом интересном из мира Python-разработки. Спасибо, что вы с нами, и приятного чтения!</p> <h2>Привет от SkyNet</h2> <p>Сколько человечество существует, столько оно любит развлекать себя нерешаемыми задачами. Алхимики пытались создать магистериум, он же великий эликсир, он же философский камень. Целью было превращать любой металл в золото, быть универсальным лекарством и продлевать жизнь. Такой же привлекательной и неосуществимой была идея вечного двигателя, perpetuum mobile. И если в 1635 году первый патент на такое устройство выдали, то к 1775 заявки принимать перестали. Всем к тому времени стало очевидно, что создать такое устройство невозможно.</p> <p>Современная золотая мечта — создание сильного ИИ, умеющего принимать решения и действовать в условиях неопределённости. Такой ИИ должен уметь обучаться, владеть естественным языком и обладать иными, присущими человеку способностями. Фактически, люди пытаются создать людей, только с кремниевыми мозгами, предполагая, что те будут служить инструментом для решения сложных задач.</p> <p>Технологии обработки естественного языка за последние пару лет совершили качественный скачок в развитии. Это привело к созданию больших языковых моделей и проектов на их основе, что кажется дорогой к исполнению наших «мечт».</p> <p>Один из таких проектов привлёк наше внимание своей необычностью. Цель <a href="https://github.com/emrgnt-cmplxty/Automata" rel=" noopener" target="_blank">Automata</a> — создать ИИ-программиста, который будет самостоятельно проектировать, писать, тестировать и совершенствовать сложные системы. При этом он сможет самостоятельно обучаться, а также дорабатывать свой собственный код, существенно повышая свою автономность и способность к изобретению новых алгоритмов. Таким образом, если проект достигнет успеха, то Automata станет первым в мире, полностью автономным ИИ.</p> <p><img alt="Automata " data-entity-type="file" data-entity-uuid="be5d21fc-4ebc-4390-a154-58ce49f66de0" width="1942" height="1238" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/s6du7juy.png" /></p> <p>За основу взяты большие языковые модели, такие как GPT-4 и векторная база данных. По замыслу разработчиков этого достаточно для создания системы, способной самостоятельно искать, писать и документировать код. Авторы вдохновились теорией автоматов, гласящей, что код по своей сути может быть формой памяти и потенциально привести к созданию Общего ИИ (General AI). Станет ли это концом человечества, как нас предупреждал Стивен Хокинг, или нет — вопрос остаётся открытым. Но мы будем периодически наведываться в репозиторий. Просто так, на всякий случай.</p> <h2>Так ли хорош Mojo</h2> <p>В мае 2023 интернет вскипел от хвалебных постов в адрес нового языка программирования <a href="https://www.modular.com/mojo" rel=" noopener" target="_blank">Mojo</a>. Ему стали пророчить будущее величайшего достижения в Computer Science, а его релиз будет главным событием в мире разработки программного обеспечения. Демоверсия примеров кода на Mojo показала результат в 35’000 раз быстрее, чем на обычном Python. Мы не стали верить этому на слово и решили не спешить с выводами. Предлагаем посмотреть на Mojo без розовых очков, когда шумиха уже улеглась.</p> <p>Mojo разрабатывается стартапом Modular, во главе которого стоит Крис Лэттнер. Ранее он был ключевым разработчиком LLVM, MLIR, Clang и языка Swift. Такой послужной список, вместе с опытом работы в Google, Tesla и Apple, говорит о крайне высокой квалификации. Второй основатель Тим Дэвис, также опытный разработчик, ранее работал над Tensorflow. Остальные участники проекта зарекомендовали себя в сфере разработки компиляторов, фреймворков и машинного обучения.</p> <p>Ключевым элементом языка будет <a href="https://mlir.llvm.org/" rel=" noopener" target="_blank">MLIR</a>. Это компилятор, в основе которого лежит идея расширяемости и возможности переиспользования инфраструктуры. Изобретать собственный синтаксис не стали, взяв его из Python. Это решение позволит не придумывать велосипед, а сразу сделать Mojo привычным для всех, кто уже программирует на Python. Более того, используется метод <a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food#:~:text=Eating%20your%20own%20dog%20food%20or%20%22dogfooding%22%20is%20the%20practice,one&#039;s%20own%20products%20or%20services." rel=" noopener" target="_blank">Dogfooding</a> (Eating our own dog food), при котором создание языка ведется с помощью уже созданных элементов этого языка. Примерно также, как в Julia всё построено с использованием Julia.</p> <p>Вместо однозначно определённой системы типов будет гибрид между статической и динамической. Если для определения функции разработчик использует ключевое слово fn, то будет применена высокопроизводительная статическая типизация. В этом случае нужно будет определить тип каждого идентификатора, а Mojo сможет оптимизировать создаваемый машинный код. Если использовано слово def — останется обычная динамическая типизация и типы будут выбираться языком самостоятельно с возможностью их менять во время выполнения кода. Так можно будет точечно ускорять конкретные функции, не слишком усложняя код.</p> <p>Поразительные итоги демоверсии, с одной стороны, выглядят чистым маркетингом. Расчёт множества Мандельброта — абсолютно синтетический бенчмарк. В реальном приложении такого феноменального ускорения достичь вряд ли получится. С другой стороны, команда, ведущая разработку Mojo, имеет опыт и экспертизу работы над сложными проектами. Это, в свою очередь, позволяет верить в успех. Волна хайпа утихла, но скорее всего мы ещё услышим о Mojo и о том, чего удалось достичь команде Modular.</p> <h2>Альтернативное мнение: asyncio</h2> <p>Asyncio решил много проблем в Python. Асинхронное программирование стало нативным, частью языка. Костыли больше не требовались, а множество разработчиков вздохнули с облегчением. Но не всем это нововведение пришлось по душе. Некоторые программисты, такие как Чарльз Лейфер, даже спустя 8 лет <a href="https://charlesleifer.com/blog/asyncio/" rel=" noopener" target="_blank">считают</a> его дестабилизирующим фактором, порождающим ужасный дизайн.</p> <p>Основной проблемой Чарльз называет то, что asyncio нельзя внедрять частично. Если архитектура приложения заранее предусматривала асинхронность, то особых сложностей не будет. В ином случае возникает ситуация, когда применяемые библиотеки не совместимы с asyncio или же предоставляют собственную реализацию асинхронности. Таким образом мейнтейнеру приходится или самостоятельно подружить ту или иную библиотеку с asyncio, или добавить в приложение дублирующий код. Первое приводит к появлению плеяды незрелых библиотек, а второе — не лучший вариант, с точки зрения архитектуры.</p> <p>Ещё одна проблема в том, что внедрение асинхронности сильно увеличивает сложность. Повышается риск даже небольших ошибок, которые легко разделят на ноль возможный выигрыш в производительности. При этом считается, что для создания современного веб-приложения асинхронность — очевидная необходимость. Но практическая польза от этого может быть незначительной. Это скорее превратилось в тренд, заражающий всё вокруг.</p> <p>Если же асинхронность именно то, что вам нужно, то есть альтернативный способ её добиться. Библиотека <a href="https://www.gevent.org/" rel=" noopener" target="_blank">gevent</a> отличается от asyncio тем, что преобразует все блокирующие вызовы в неблокирующие и возвращает управление в event loop. Интерфейс gevent сильно напоминает treading module из Python, что делает его знакомым для программистов, ранее использовавших параллелизм на основе потоков. Ну а использовать его или нет — решение, в любом случае, за вами.</p> <h2>Подсказываем в CLI</h2> <p>Закончим наш дайджест полезным инструментом — библиотекой <a href="https://github.com/treykeown/arguably" rel=" noopener" target="_blank">arguably</a>. Она помогает превратить ваши функции и строки документации в интерфейсы командной строки. С интеграцией не должно возникнуть никаких проблем. Всё, что скрипт должен преобразовать, надо задекорировать с помощью @arguably.command, а затем вызвать с помощью arguably.run().</p> <p>Возьмём небольшой пример, назовём его intro.py:</p> #!/usr/bin/env python3 import arguably @arguably.command def some_function(required, not_required=2, *others: int, option: float = 3.14): """ this function is on the command line! Args: required: a required argument not_required: this one isn't required, since it has a default value *others: all the other positional arguments go here option: [-x] keyword-only args are options, short name is in brackets """ print(f"{required=}, {not_required=}, {others=}, {option=}") if __name__ == "__main__": arguably.run() <p>Результатом выполнения кода станет следующее:</p> user@machine:~$ ./intro.py -h usage: intro.py [-h] [-x OPTION] required [not-required] [others ...] this function is on the command line! positional arguments: required a required argument (type: str) not-required this one isn't required, since it has a default value (type: int, default: 2) others all the other positional arguments go here (type: int) options: -h, --help show this help message and exit -x, --option OPTION keyword-only args are options, short name is in brackets (type: float, default: 3.14) <p>Библиотека arguably автоматически создала подсказку, которая позволит пользователям сходу разобраться, какие аргументы необходимо указать и в каком формате. Отдельно отметим, что поддерживаются разные языки разметки документации: reStructuredText, Google, Numpydoc и Epydoc.</p> <p>Установка производится через pip:</p> pip install arguably <p>Если эта библиотека вам понравилась, то не забудьте заглянуть в репозиторий и поставить звёздочку. Уверены, что автору будет приятно.</p> <h2>Интересно посмотреть</h2> <p>Пропустили наш предыдущий митап? Не страшно! Видеозаписи докладов уже выложены на нашем <a href="https://www.youtube.com/@EvroneDevelopment/" rel=" noopener" target="_blank">YouTube-канале</a> в кинематографическом качестве 4K и со студийным звуком.</p> <p>Александр Мещеряков из Сinimex рассказал, как развертывать модели с использованием геопространственных данных и отобразить исходную информацию на карте с помощью визуализации геоданных:</p> <p>Дмитрий Савостьянов из Artifactory поделился опытом использования ML-модели прогнозов платежей клиентов и системы предсказания спроса, разработанной в компании. Монетизация в мобильных играх строится на внутриигровых продажах, обычно платят не более 10% пользователей. Поэтому очень важно удерживать платящих игроков. Для такой предиктивной аналитики геймдевы решили использовать машинное обучение:</p> <p>Мария Изофатова из Мегафон объявила месяц борьбы с уязвимостями кластера Apache Hadoop: репартиционирование (проблема мелких файлов), автоочищение таблиц на кластере, настройка конфигурации PySpark, анализ запущенных Spark application и внутреннего кода:</p> <p>Подписывайтесь и ставьте 🔔колокольчик, чтобы получать уведомления о будущих трансляциях и видео! А ещё присоединяйтесь к <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Telegram-каналу</a> и будьте в курсе всех наших будущих мероприятий.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>11 октября 2023</p> <p>Рады сообщить, что у нас запланирован осенний Python Meetup. Программа мероприятия формируется. Заявки на участие спикера <a href="https://docs.google.com/forms/d/e/1FAIpQLSedDbmB8mAtDb5_bKgUnmh8f6apOYXDsdvtXt1JPz7VoWqX2A/viewform?usp=sf_link" rel=" noopener" target="_blank">принимаются</a> до 20 сентября.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-4?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_7_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_7_2023" rel=" noopener" target="_blank">Подробнее</a></p> Wed, 05 Jul 2023 12:53:11 +0000 Evrone digest /20230705 Расширяем кругозор https://digest.evrone.ru/20230607 <img src="/sites/default/files/styles/card_m/public/2023-06/ghdmjghfdbx.png?itok=akj-qcP3" width="960" height="540" alt="dhjg" loading="lazy" typeof="Image" /> <br /> <p>В июньском дайджесте расскажем об автоматизации часто используемых действий и приёмах, которые можно почерпнуть из Rust. Также поделимся простой и эффективной библиотекой для интерактивных подсказок и узнаем, какое будущее готовится для Python на мобильных платформах. Приятного чтения!</p> <h2>Лайфхаки с Makefile</h2> <p>При <a href="https://evrone.ru/technologies/python" rel=" noopener" target="_blank">разработке любого проекта на Python </a>есть масса рутинных операций: тесты, запуск приложения в контейнере или прогон кода линтером. И не стоит плодить лишние сущности в виде shell-скриптов под каждую такую задачу. Можно использовать встроенный в IDE task runner или даже поставить какой-то внешний инструмент, но есть решение элегантнее и проще. В состав любого Linux-дистрибутива или macOS с древних времён входит такая штука, как Makefile. Её типичное применение — собирать код на C, но де-факто это крутое средство автоматизации любых задач.</p> <p>Проще всего объяснить, как это работает, на примере кода. Идеальный пример был<a href="https://antonz.ru/makefile/"> найден</a> в блоге Антона Жиянова, <a href="https://evrone.ru/blog/articles/hire-python-developers" rel=" noopener" target="_blank">разработчика на Python</a> и Golang. Вот как может выглядеть простейший Makefile: </p> coverage: ## Run tests with coverage coverage erase coverage run --include=dadata/* -m pytest -ra coverage report -m deps: ## Install dependencies pip install black coverage flake8 mypy pylint pytest tox lint: ## Lint and static-check flake8 dadata pylint dadata mypy dadata push: ## Push code with tags git push &amp;&amp; git push --tags test: ## Run tests pytest -ra <p>Прогон несколькими линтерами и тестирование? Легко: </p> $ make lint coverage <p>Запушить с тегами в репу? Ещё проще: </p> $ make push <p>Из примера видно, что можно создавать цепочки действий, каждое из которых будет выполнено в отдельном подпроцессе (как в coverage или lint). Если надо выполнить связанную между собой цепочку действий, то объединение делается через два амперсанда &amp;&amp; (как в секции push).</p> <p>Внутри этого же Makefile можно легко определить зависимости между задачами. Тут, например, тесты не будут запущены, пока не выполнен линтинг: </p> test: lint pytest -ra <p>Есть даже возможность явного вызова задач прямо внутри Makefile: </p> lint: flake8 dadata pylint dadata mypy dadata test: pytest -ra prepare: make lint make test <p>Освоив эти нехитрые приёмы, можно переходить к более сложным трюкам. В этом поможет статья<a href="https://ricardoanderegg.com/posts/makefile-python-project-tricks/" rel=" noopener" target="_blank"> Makefile tricks for Python projects</a>. Там вы найдёте полезные советы не только по составлению Makefile, но и по настройке оболочки операционной системы. Например, для BASH можно флагами отключить встроенные правила и добавлять дополнительную информацию в вывод, если операция завершилась неудачей: </p> SHELL := bash .SHELLFLAGS := -eu -o pipefail -c MAKEFLAGS += --warn-undefined-variables MAKEFLAGS += --no-builtin-rules <p>Резюмируем: освоить создание Makefile полезно любому Python-разработчику. Этот, странный на первый взгляд, инструмент умеет отлично упрощать жизнь. Ну а главное — скорее всего он уже есть на вашей рабочей машине и готов к работе без дополнительных танцев с бубном.</p> <h2>Пишем в стиле Rust</h2> <p>Всю жизнь писали на Python, а потом решили попробовать Rust? Скорее всего вы испытаете те же чувства, какие испытывает хулиган, оказавшись в английской школе 19го века. Величественно, строго и могут высечь розгами (вспомните, как наказывали Тома Сойера).</p> <p>Строгость системы типов и другие особенности языка вначале доставляют много боли и страданий. Но если все требования Rust удовлетворены, это гарантирует, что код будет работать очень быстро, и не упадёт по неизвестной причине. Значит ли это, что надо бросить всё и срочно учить другой язык? Вряд ли! А вот привнести немного порядка и строгости в Python вы можете самостоятельно, взяв за основу те же концепции, которые применены в Rust.</p> <p>Начать можно с малого — подсказок типа. Возьмём вот такую простейшую функцию: </p> def find_item(records, check): <p>Эта строка несёт в себе очень мало информации. Records — это список, словарь или вообще соединение с базой данных? А что за check? Это булево значение или какая-то другая функция? Если функция, что она вернёт? А если сбой, то получим ли мы исключение или None? Масса вопросов и ноль ответов. Теперь давайте перепишем эту функцию на аналогичную. А на вопросы сразу ответим, используя встроенный механизм подсказок: </p> def find_item( records: List[Item], check: Callable[[Item], bool] ) -&gt; Optional[Item]: <p>Стало понятно, что такое records и check. А главное, мы сразу видим, какого они должны быть типа. Написать такой код легко и не слишком долго. Зато потом в нём легко будет разобраться и найти потенциальные ошибки. Теперь, когда у нас есть удобное и внятное описание, пришла пора сделать интерфейсы более точными и защищёнными от неожиданностей. Вернуть несколько значений (или одно сложное значение) из функции можно несколькими способами. Проще всего вернуть кортеж или словарь, но оба этих способа на выходе дадут нечто, что придётся изучать. Вот пример кортежа: </p> def find_person(...) -&gt; Tuple[str, str, int]: <p>Вернулись три каких-то значения. Придётся внимательно изучать функцию, чтобы выяснить их значение. Словарь тоже не решит ситуацию: </p> def find_person(...) -&gt; Dict[str, Any]: ... return { "name": ..., "city": ..., "age": ... } <p>Тут ещё хуже. Мы не знаем ни количество, ни типы отдельных атрибутов. Если функцию изменить, то ключи в возвращаемом словаре могут быть переименованы или удалены. Выяснить потом тип каждого ключа можно будет только вручную, что долго и сложно.</p> <p>Решением станет возвращать строго типизированный объект. Каждый параметр такого объекта должен иметь ассоциированный тип. Это автоматически подводит нас к решению о создании класса, а чтобы не усложнять жизнь, его можно создать при помощи dataclasses: </p> @dataclass class City: name: str zip_code: int @dataclass class Person: name: str city: City age: int def find_person(...) -&gt; Person: <p>Так гораздо информативнее. Мы сразу же получаем явное описание того, что возвращает функция. Автодополнение IDE начнёт работать эффективнее, показывая имена и типы атрибутов. При рефакторинге и изменении атрибутов средство проверки типов и IDE укажут на все места, которые нужно изменить. Даже запускать программу не потребуется. Хотите узнать больше, тогда рекомендуем заглянуть в статью<a href="https://kobzol.github.io/rust/python/2023/05/20/writing-python-like-its-rust.html" rel=" noopener" target="_blank"> Writing Python like it's Rust</a> чешского программиста Якуба Беранека (Jakub Beránek).</p> <h2>CLI prompts без ncurses</h2> <p>Мы в Evrone любим удобные и легковесные инструменты. Сегодня кратко расскажем об одной простой и красивой библиотеке<a href="https://github.com/Exahilosys/survey"> survey</a> для создания подсказок. Её автор вдохновлялся<a href="https://github.com/go-survey/survey" rel=" noopener" target="_blank"> одноимённой библиотекой</a> из языка Go. С помощью survey можно создавать интерактивные подсказки с множеством дополнительных возможностей. При этом она самодостаточна и не требует дополнительных зависимостей, таких как ncurses. </p> <p><img alt="survey" data-entity-type="file" data-entity-uuid="e57d32ff-1873-43db-a948-ba2c84ae97f5" width="1224" height="552" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/image3_2.gif" /></p> <p>Библиотека имеет хорошо структурированную<a href="https://survey.readthedocs.io/reference.html"> документацию</a> с кучей гифок, демонстрирующих для чего её можно применять. Используется принцип конструктора, где каждая фича представлена в виде виджета. Комбинируя их, можно создавать действительно удобные пользовательские интерфейсы для консоли. Там учтено множество моментов, основанных на опыте использования разных операционных систем. Так, например, пользователи привыкли, что при введении паролей, они видят количество символов, замаскированных звёздочками. В survey есть соответствующий виджет <a href="https://survey.readthedocs.io/reference.html#survey.routines.conceal">Conceal</a>: </p> value = survey.routines.conceal('Password: ') print(f'Answered {value}.') <p><img alt="sdfg" data-entity-type="file" data-entity-uuid="777dde95-b612-4e8b-a128-145abf5370ad" width="926" height="51" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/dghnsrtbs35.gif" /></p> <p>Если стоит задача сделать удобную форму, то это легко делается одноимённым виджетом <a href="https://survey.readthedocs.io/reference.html#survey.routines.form">Form</a>: </p> form = { 'name': survey.widgets.Input(), 'price': survey.widgets.Count(), 'type': survey.widgets.Select(options = ('food', 'stationary', 'tobacco', 'literature')) } data = survey.routines.form('Item Data: ', form = form) <p><img alt="fghd" data-entity-type="file" data-entity-uuid="cee5bc12-734d-41c9-b660-f8ef1f36bbd1" width="926" height="199" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/sfgndghdhndghn.gif" /></p> <p>Также легко сделать прогресс-бар, список с возможностью выбора одного или нескольких значений и прочие элементы, вроде ввода даты/времени. Так что если вы решили добавить консольному интерфейсу своего приложения удобства, то эта небольшая библиотека точно справится.</p> <h2>Python на мобильных</h2> <p>Проблема экосистем для приложений в том, что друг с другом они несовместимы и каждая из них предлагает собственные средства разработки. Раньше вообще предполагалось, что если вы пишете приложение под десктопные системы, оно не заработает на мобильных устройствах.</p> <p>Время идёт, а легче не становится. Среди мобильных экосистем всё ещё жёсткая конкуренция, так что если вы пишете под Android на каком-нибудь Kotlin, то на iOS такое приложение простым способом не портировать. Частично ситуацию решает фреймворк Flutter для языка Dart. Он позволяет иметь единую кодовую базу, но при этом созданные приложения заработают и на десктопных системах, и на смартфонах из разных экосистем.</p> <p>Проект <a href="https://beeware.org/" rel=" noopener" target="_blank">BeeWare</a> служит той же цели и даёт возможность разрабатывать приложения на Python, которые бы работали на разных мобильных устройствах и могли бы нативно задействовать возможности этих устройств. Эта идея возникла очень давно, но до недавнего времени проект выглядел как чьё-то хобби и поддерживался энтузиастами во главе с Расселом Кит-Маги (Russel Keith-Magee). Теперь же компания Anaconda увидела потенциал BeeWare и стала его финансировать, что позволило Расселу заниматься им <a href="https://beeware.org/news/buzz/exciting-news-for-the-future-of-beeware/" rel=" noopener" target="_blank">full-time</a> вместе с коллегой, Малькольмом Смитом (Malcolm Smith).</p> <p>На Python Language Summit в этом году <a href="https://pyfound.blogspot.com/2023/05/the-python-language-summit-2023-python.html" rel=" noopener" target="_blank">прозвучало</a> интересное предложение. Рассел предложил включить Android и iOS в список платформ уровня Tier 3 от CPython в Python 3.13. Переводя с «питонячьего бюрократического», это означает, что как минимум один основной разработчик CPython возьмёт на себя обязательство поддерживать работу интерпретатора на этих платформах.</p> <p>Точно такой же уровень поддержки уже присвоен платформам emscripten, WASI и FreeBSD. Основная проблема и препятствие на этом пути — запуск тестов на мобильных платформах в CI. Именно это препятствие Рассел устранил, создав <a href="https://beeware.org/project/projects/tools/briefcase/">Briefcase</a>. Будучи одним из инструментов упаковки и разработки BeeWare, Briefcase может закрыть вопрос с тестированием.</p> <p>Разумеется, впереди будет ещё масса специфических вопросов. Например, iOS полностью аутентична, а вот Android во многом схож с Linux. С первой ОС всё понятно и она может быть легко указана, как sys.platform == “ios”. А вот Android может быть либо указан как sys.platform == “android”, либо как sys.platform == “linux”.</p> <p>Второй вариант, по словам Рассела, оптимален, поскольку большая часть кода будет работать на Android сразу, даже если возможность запуска на этой платформе не учитывается. Так что если предложение будет принято, возможно мы получим возможность писать приложения на Python, которые будут отлично работать на всех современных смартфонах.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>28 июня 2023</p> <p>Рады сообщить, что у нас запланирован летний Python Meetup. Программа мероприятия формируется. Заявки на участие спикера <a href="https://docs.google.com/forms/d/e/1FAIpQLSedDbmB8mAtDb5_bKgUnmh8f6apOYXDsdvtXt1JPz7VoWqX2A/viewform?usp=sf_link" rel=" noopener" target="_blank">принимаются</a> до 10 июня. Видео с предыдущего митапа в студийном качестве 4K уже выложены на нашем <a href="https://www.youtube.com/@EvroneDevelopment" rel=" noopener" target="_blank">YouTube-канале</a>.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-3?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_6_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_6_2023" rel=" noopener" target="_blank">Подробнее</a></p> Wed, 07 Jun 2023 12:25:31 +0000 Evrone digest /20230607 Mastodon-бот, urllib3 v2.0.0 и TOTP https://digest.evrone.ru/20230510 <img src="/sites/default/files/styles/card_m/public/2023-05/image1.png?itok=WVVor4o1" width="960" height="540" alt="Mastodon-бот, urllib3 v2.0.0 и TOTP" loading="lazy" typeof="Image" /> <br /> <p>В сегодняшнем дайджесте посмотрим, как создать бота для Mastodon, отпразднуем с сообществом выход urllib3 v2.0.0 и расскажем про реализацию алгоритма TOTP всего в 20 строках кода.</p> <h2>Разработка Mastodon-бота на Python</h2> <p>Илон Маск продолжает агрессивную монетизацию Twitter. Доступ к API стал платным и это поставило крест на создании бесплатных ботов для интерактивных коммуникаций. Свято место пусто не бывает — всё больше разработчиков <a href="https://blog.tiagorangel.com/creating-a-mastodon-bot-with-python" rel=" noopener" target="_blank">выбирают</a> в качестве платформы децентрализованную self-hosted социальную сеть <a href="https://joinmastodon.org/" rel=" noopener" target="_blank">Mastodon</a>. Каждый сервер (участник сети) может иметь собственные правила и не подчиняется какой-то единой политике.</p> <p>Чтобы попрактиковаться в создании Mastodon-ботов, можете попробовать инстанс <a href="https://botsin.space/" rel=" noopener" target="_blank">botsin.space</a>. Список правил, которые необходимо соблюдать людям и ботам описан в их <a href="https://botsin.space/about" rel=" noopener" target="_blank">Code-of-Conduct</a>. Чтобы не изобретать велосипед, в качестве оболочки для API имеет смысл выбрать библиотеку <a href="https://github.com/halcy/Mastodon.py" rel=" noopener" target="_blank">Mastodon.py</a>. </p> <p>Минимальный пример в стиле Hello, world! будет выглядеть так:</p> from mastodon import Mastodon # Create an instance of the Mastodon class mastodon = Mastodon( access_token='your_access_token_here', api_base_url='https://your.instance.url' ) # Post a new status update mastodon.status_post('Hello, Mastodon!') <p>Автоматический ответ на упоминания имени пользователя в toots (аналог твита в Twitter) можно выразить вот таким кодом:</p> # Define a function to handle mentions def handle_mention(status): if '@your_bot_username' in status.content: mastodon.status_post('@' + status.account.username + ' Hello there!') # Start streaming for mentions mastodon.stream_user(handle_mention) <p>Этого уже достаточно для построения простейшего бота. К тому же на подобный триггер можно назначить любое действие. Если запустить подобное приложение на одноплатном компьютере с внешним дисплеем, можно отображать на нём количество упоминаний. Взаимодействие социальных сетей с реальными устройствами, по нашему мнению, отличное пространство для экспериментов.</p> <h2>urllib3 v2.0.0 вышел в релиз</h2> <p>HTTP-клиент urllib3, о котором мы неоднократно <a href="https://digest.evrone.ru/20230110" rel=" noopener" target="_blank">упоминали</a> в наших <a href="https://digest.evrone.ru/20220708" rel=" noopener" target="_blank">дайджестах</a>, получил долгожданное обновление до версии 2.0.0. Выпущенный 12 лет назад, он стал настоящим сокровищем и был загружен более 8 млрд раз. За прошедшие годы разработчики пришли к выводу, что необходимо провести большой рефакторинг и результатом стала версия 2.0.0. Мы детально взглянули на релиз и готовы поделиться некоторыми выводами.</p> <p>Просьбы пользователей о появлении высокоуровневой функции urllib3.request() были услышаны. Теперь можно делать HTTP-запросы и не беспокоиться о сложности процессов, лежащих в основе функции. В сети уже появились <a href="https://stackabuse.com/guide-to-sending-http-requests-in-python-with-urllib3/">гайды</a> с примерами, основанными на новой фиче, вот один из примеров:</p> import urllib3 resp = urllib3.request("GET", "https://example.com") print(resp.status) # 200 print(resp.headers.get("Content-Type")) # text/html; charset=UTF-8 <p>Кажется, <a href="https://ru.wikipedia.org/wiki/KISS_(%D0%BF%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF)" rel=" noopener" target="_blank">принцип KISS</a> здесь был задействован на полную катушку. Второй важной и полезной возможностью стала встроенная поддержка JSON в API-интерфейсах запросов и ответов. Это автоматически упрощает код и позволяет взаимодействовать с API-интерфейсами HTTP через JSON:</p> import urllib3 resp = urllib3.request( "POST", "https://httpbin.org/anything", # The 'json' parameter encodes the JSON into the body # and sets the 'Content-Type' to 'application/json'. json={"key": "value"} ) # The HTTPResponse.json() method decodes JSON in the body # and loads the data into a Python object. print(resp.json()) <p>Отдельно декодировать JSON не требуется, мы сразу получаем на выходе объект с данными:</p> { "headers": { "Accept-Encoding": "identity", "Content-Length": "15", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "python-urllib3/2.0.0" }, "json": { "key": "value" }, "method": "POST", "url": "https://httpbin.org/anything" } <p>Красота, да и только. Ну и третье существенное изменение коснулось отсутствующего в Python понятия <a href="https://ru.wikipedia.org/wiki/%D0%A2%D0%B8%D0%BF%D0%BE%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C" rel=" noopener" target="_blank">безопасности типов</a>. Если функция принимает строковый параметр, а вы в неё отправите целочисленный, то интерпретатор не поднимет тревоги. Правда, функция при этом, скорее всего, тоже не заработает правильно. Начиная с версии 2.0.0, urllib3 обзавёлся строгими подсказками типов.</p> <p>Кстати, команда разработчиков ещё пару лет назад написала <a href="https://sethmlarson.dev/tests-arent-enough-case-study-after-adding-types-to-urllib3" rel=" noopener" target="_blank">статью</a> о том, с какими нестандартными проблемами они столкнулась в процессе реализации этой фичи. Ну а если вам интересны все нововведения второй версии, советуем заглянуть в <a href="https://github.com/urllib3/urllib3/releases" rel=" noopener" target="_blank">Changelog</a> релиза.</p> <h2>TOTP в 20 строках кода</h2> <p>Алгоритм <a href="https://en.wikipedia.org/wiki/Time-based_one-time_password" rel=" noopener" target="_blank">TOTP</a> (Time-Based One-Time Password) —«священный грааль» инициативы <a href="https://en.wikipedia.org/wiki/Initiative_for_Open_Authentication" rel=" noopener" target="_blank">OATH</a> (Initiative for Open Authentication). Этот алгоритм применяется в качестве составляющей двухфакторной или мультифакторной авторизации, дополняя традиционные механизмы на основе паролей, кодовых фраз, аппаратных токенов и прочих.</p> <p>TOTP-коды остаются действительными лишь короткий отрезок времени, после чего «протухают». Штатно код меняется каждые 30 секунд. Если школьник Вася перехватит данные с помощью трояна, то у него будет лишь несколько секунд, чтобы ими воспользоваться. Не печалься, Вася! Ещё станешь хорошим хакером! А мы пока посмотрим на внутреннее устройство TOTP.</p> <p>«Сердцем» TOTP является алгоритм HOTP (HMAC-based One-Time Password). HMAC, как часть этого алгоритма, гарантирует, что в случае перехвата сообщения атакующий не сможет угадать длину или расшифровать сообщение без наличия ключа или кода. Если вы планируете задействовать TOTP, советуем обратить внимание на проект <a href="https://github.com/susam/mintotp" rel=" noopener" target="_blank">MinTOTP</a>. Авторы явно задались целью сделать настолько минималистичный код, насколько это возможно. Полноценная реализация заняла всего 20 строк кода (30 с начальным шебангом и пустыми строками):</p> #!/usr/bin/env python3 import base64 import hmac import struct import sys import time def hotp(key, counter, digits=6, digest='sha1'): key = base64.b32decode(key.upper() + '=' * ((8 — len(key)) % 8)) counter = struct.pack('&gt;Q', counter) mac = hmac.new(key, counter, digest).digest() offset = mac[-1] &amp; 0x0f binary = struct.unpack('&gt;L', mac[offset:offset+4])[0] &amp; 0x7fffffff return str(binary)[-digits:].zfill(digits) def totp(key, time_step=30, digits=6, digest='sha1'): return hotp(key, int(time.time() / time_step), digits, digest) def main(): args = [int(x) if x.isdigit() else x for x in sys.argv[1:]] for key in sys.stdin: print(totp(key.strip(), *args)) if __name__ == '__main__': main() <p>Модуль hmac нужен для реализации HOTP и берётся из стандартной библиотеки. HOTP принимает на вход секретный ключ, закодированный в Base32 и счётчик. На выходе выдаётся 6 цифр. Функция TOTP фактически служит “обёрткой” для HOTP с подсчётом временных интервалов, начиная с Unix epoch (1970-01-01 00:00:00 UTC). Практично, удобно… Рекомендуем!</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>28 июня 2023</p> <p>Рады сообщить, что у нас запланирован летний Python Meetup. Программа мероприятия формируется. Заявки на участие спикера <a href="https://docs.google.com/forms/d/e/1FAIpQLSfn0NRlkwd4PpSUdg4kK1t67ooUmqDQo1sTQ-yd2ZLL7Y0LiQ/viewform?usp=sf_link" rel=" noopener" target="_blank">принимаются</a> до 10 июня. Видео с предыдущего митапа в студийном качестве 4K уже выложены на нашем <a href="https://www.youtube.com/@EvroneDevelopment" rel=" noopener" target="_blank">YouTube-канале</a>.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-3?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_5_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_5_2023" rel=" noopener" target="_blank">Подробнее</a></p> Wed, 10 May 2023 13:16:55 +0000 Evrone digest /20230510 Pandas 2.0 и асинхронный агностицизм https://digest.evrone.ru/20230407 <img src="/sites/default/files/styles/card_m/public/2023-04/image1.png?itok=m2oM1pLB" width="960" height="540" alt="Pandas 2.0 и асинхронный агностицизм" loading="lazy" typeof="Image" /> <br /> <p>Апрель 2023 порадовал мажорным обновлением Pandas, самой известной библиотеки для анализа данных. Ещё мы рассказали о трудностях дистрибуции <a href="https://evrone.ru/technologies/python" rel=" noopener" target="_blank">Python-приложений</a> в экосистеме macOS, способах запуска приложений в браузере с помощью PyScript и асинхронном фреймворке Textual.</p> <h2>Долгожданный Pandas 2.0</h2> <p>Самая популярная библиотека для анализа данных <a href="https://github.com/pandas-dev/pandas/releases/tag/v2.0.0" rel=" noopener" target="_blank">обновилась</a> до версии 2.0. Основным изменением стала интеграция с <a href="https://arrow.apache.org/" rel=" noopener" target="_blank">Apache Arrow</a>. Это такой унифицированный формат хранения данных в памяти. Ранее Pandas использовал только библиотеку <a href="https://numpy.org/" rel=" noopener" target="_blank">NumPy</a>, которая была не всегда эффективной при работе с такими структурами данных, как <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html" rel=" noopener" target="_blank">DataFrame</a>.</p> <p>«Если хочешь сделать что-то хорошо, сделай это сам», — эта цитата Фердинанда Порше отлично отражает то, что сделал создатель Pandas, Уэс МакКинни (Wes McKinney). 10 лет назад он выступал с докладом о проблемах производительности, а спустя 4 года стал соучредителем Apache Arrow. Новый релиз соединил в себе сильные стороны обоих проектов.</p> <p>Pandas часто критиковали за несколько особенностей. Отсутствующие значения долгое время были «головной болью» для специалистов по анализу данных. Они вызывали неявное изменение типа данных. Отсутствующие значения могли иметь разный тип, что в конечном итоге влияло на конечный dtype. Arrow решает эту проблему «из коробки»:</p> In [1]: df2 = pd.DataFrame({'a':[1,2,3, None]}, dtype='int64[pyarrow]') In [2]: df2.dtypes Out[2]: a int64[pyarrow] dtype: object In [3]: df2 Out[3]: a 0 1 1 2 2 3 3 &lt;NA&gt; <p>Второй особенность, за которую Pandas часто ругали — неэффективное управление строками. Оно и понятно — NumPy создавался вовсе не для обработки строк, а для числовых расчётов. Так что столбец со строковыми данными представлял собой набор указателей PyObject. Сами же данные были хаотично разбросаны по куче. Ни о какой эффективности тут речь, разумеется, не идёт. Промахи кэша и увеличенное потребление памяти — два постоянных спутника.</p> <p>Чем больше было данных, тем ситуация становилась хуже. Даже экспериментальное расширение <a href="https://pandas.pydata.org/docs/reference/api/pandas.StringDtype.html" rel=" noopener" target="_blank">StringDtype</a> не улучшило ситуацию. Apache Arrow архитектурно лишён этих недостатков и обращается с памятью эффективнее. Приятным бонусом стало существенное увеличение скорости (до 10 раз быстрее, чем NumPy) и уменьшение использования памяти (более чем в 2 раза).</p> <p>Также внедрили механизм <a href="https://pandas.pydata.org/docs/user_guide/copy_on_write.html" rel=" noopener" target="_blank">CoW (Copy-on-Write)</a>. Он часто используется в других системах для уменьшения накладных расходов на копирование. Это повышает безопасность данных, при использовании операций индексирования, а также производительность при совместной работе.</p> <h2>Пишем приложения для macOS</h2> <p>Python считается одним из наиболее универсальных языков. На нём можно написать всё что угодно. Но иногда простая задача написать приложение под macOS и распространить его, может превратиться в целый квест. Такая история была <a href="https://blog.glyph.im/2023/03/py-mac-app-for-real.html" rel=" noopener" target="_blank">опубликована</a> в блоге Python-разработчика Глифа Лефковица (Glyph Lefkowitz).</p> <p>Экосистема Apple кажется заточенной под правильного разработчика, пишущего проприетарный код в нативном XCode на каком-нибудь Swift и платящего за учётную запись $99 в год. Конечно же, только на оборудовании Apple.</p> <p>Если же вы на любом другом сетапе пишете приложение с открытым исходным кодом на Python в каком-нибудь VSCode или PyCharm — столкнётесь с рядом сложностей при попытке распространить его в экосистеме Apple. Чтобы подписать приложение, понадобится валидная учётная запись на портале Apple Developer. Можно использовать и <a href="https://developer.apple.com/account/resources/certificates/add" rel=" noopener" target="_blank">веб-портал</a> или ещё проще — подписать через XCode. Эта поистине монструозная IDE, весом в 11 Гб. Боль для тех, у кого нет доступа к высокоскоростному интернет-каналу.</p> <p>Предположим, всё это пройдено и приложение подписано. Возникает новое препятствие — приложение должно быть подписано самой Apple, процедура «notarization». Подпись с заверением делается с помощью усиленной среды исполнения. Последняя несовместима с множеством вещей в Python, таких как cffi или ctypes. А если в пакете есть внутренние симлинки, то вообще пиши пропало.</p> <p>Подводных камней в этом, казалось бы, простом процессе — множество. И вовсе не все они относятся к Python. Увы, сообщество разработчиков не может напрямую влиять на инструменты поставщика операционной системы. Документация, даже самая крутая, не решит все эти проблемы. Возможно, стоит создать инструмент, который бы интерактивно подсказывал и перепроверял каждый шаг разработчика на пути превращения его Python-кода в готовое к дистрибуции приложение для macOS.</p> <h2>Python в браузере</h2> <p>Всё больше интересных идей превращаются в готовые приложения с открытым исходным кодом. Проект <a href="https://pyscript.net/" rel=" noopener" target="_blank">PyScript</a> начался с идеи «Было бы круто иметь возможность запускать код на Python прямо внутри браузера». Давайте возьмём <a href="https://pyodide.org/en/stable/" rel=" noopener" target="_blank">Pyodide</a> (портированный CPython), прикрутим к нему <a href="https://webassembly.org/" rel=" noopener" target="_blank">WASM</a> и используем HTML в качестве интерфейса. Немного магии и мы получаем фреймворк для <a href="https://evrone.ru/technologies/python" rel=" noopener" target="_blank">создания приложений на Python</a>, которые будут работать везде, где есть современный браузер.</p> <p>Попробовать PyScript можно тремя способами. Самый простой — на сайте проекта есть <a href="https://pyscript.net/examples/" rel=" noopener" target="_blank">18 демонстрационных примеров</a>. Запуск любого приводит к открытию вкладки, загрузке Pyodide и запуску заранее написанного кода.</p> <p>Второй вариант чуть интереснее — бета-версия сервиса, размещённая на <a href="https://pyscript.com/" rel=" noopener" target="_blank">pyscript.com</a>. Чтобы начать работу, потребуется только создать учётную запись. После этого вы получите доступ к платформе, на которой можно вести разработку приложений и сразу же их запускать прямо в браузере. </p> <p><img alt="pyscript" data-entity-type="file" data-entity-uuid="3a2f0c89-04a2-41d2-a934-1df5c07262a0" width="893" height="436" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/image2_11.png" /></p> <p>Наиболее полезная функция такой платформы — она генерирует уникальные адреса для каждого проекта, что позволяет легко делиться результатом с другими людьми, просто пересылая ссылку. При этом будет доступно и само приложение, и его код.</p> <p>Третий же способ — локальное развёртывание. В нужную веб-страницу добавляете скрипт и таблицу стилей:</p> &lt;head&gt; &lt;link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /&gt; &lt;script defer src="https://pyscript.net/latest/pyscript.js"&gt;&lt;/script&gt; &lt;/head&gt; <p>Сам же код прописываете непосредственно в веб-странице, например:</p> &lt;py-config&gt; plugins = [ "https://pyscript.net/latest/plugins/python/py_tutor.py" ] &lt;/py-config&gt; &lt;section class="pyscript"&gt; Hello world! &lt;br&gt; This is the current date and time, as computed by Python: &lt;py-script&gt; from datetime import datetime now = datetime.now() display(now.strftime("%m/%d/%Y, %H:%M:%S")) &lt;/py-script&gt; &lt;/section&gt; <p>Сохраняете, приложение заработает. Никаких дополнительных телодвижений не требуется.</p> <h2>Не асинхронная асинхронность</h2> <p>Реализация асинхронного программирования с помощью паттерна async/await в Python 3.5 стало важным событием. С того момента можно было создавать сопрограммы, вычисления в которых не блокировали работу приложения. Это давало существенный прирост производительности. Особенность асинхронного программирования в том, что оно оптимизирует время исполнения и позволяет избежать простоев процессора.</p> <p>Но у асинхронности есть и недостатки. По <a href="https://textual.textualize.io/blog/2023/03/15/no-async-async-with-python/" rel=" noopener" target="_blank">мнению</a> эксперта по Python, <a href="https://github.com/willmcgugan" rel=" noopener" target="_blank">Уилла МакГугана (Will McGugan)</a>, основная проблема асинхронности в том, что она имеет тенденцию бесконтрольного размножения в коде. Разработчики начинают использовать async для одного-единственного вызова или ещё хуже — добавляют async просто так, на всякий случай.</p> <p>Но ведь паттерн async/await вовсе не единственная асинхронная техника. Есть ещё одна интересная, называется «Await me maybe». Она отлично работает с библиотекой <a href="https://docs.python.org/3/library/asyncio.html" rel=" noopener" target="_blank">asyncio</a>. Термин впервые был придуман Саймоном Уиллисоном (<a href="https://simonwillison.net/2020/Sep/2/await-me-maybe/" rel=" noopener" target="_blank">Simon Willison</a>). Смысл в том, чтобы асинхронная функция могла запускать callback либо с запланированной (неасинхронной) функцией, либо с корутиной (асинхронной через async def). Выглядит это следующим образом:</p> import asyncio import inspect def plain_old_function(): return "Plain old function" async def async_function(): return "Async function" async def await_me_maybe(callback): result = callback() if inspect.isawaitable(result): return await result return result async def run_framework(): print( await await_me_maybe(plain_old_function) ) print( await await_me_maybe(async_function) ) if __name__ == "__main__": asyncio.run(run_framework()) <p>Этот паттерн лёг в основу асинхронного фреймворка <a href="https://textual.textualize.io/" rel=" noopener" target="_blank">Textual</a>. Он вообще не требует от разработчика использования ключевых слов async/await, хотя и позволяет расставить их по коду. Если захотите попробовать его в деле, то гайд по быстрому старту есть <a href="https://textual.textualize.io/getting_started/" rel=" noopener" target="_blank">на сайте проекта</a>.</p> <h2>Интересно посмотреть</h2> <p>Мы рады делиться экспертизой наших специалистов. На YouTube-канале <a href="https://www.youtube.com/@evroneacademy" rel=" noopener" target="_blank">Evrone Academy</a> появилось много новых обучающих видео. Даже если вы давно пишете на Python, иногда полезно освежить знания и сверить их с другими экспертами. Ну а для новичков эти видео могут стать отличной отправной точкой.</p> <p>Короткий и ёмкий формат занятий отлично подойдёт даже тем, у кого не слишком много свободного времени. Текстовые версии лекций доступны в нашем <a href="https://habr.com/ru/users/Evrone/posts" rel=" noopener" target="_blank">блоге</a> на Хабре. Подписывайтесь и отправляйте эти видео своим друзьям, которые хотят начать изучать Python. И не забывайте нажать на «колокольчик», чтобы не пропустить новые видео.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>28 июня 2023</p> <p>Рады сообщить, что у нас запланирован летний Python Meetup. Программа мероприятия формируется. Заявки на участие спикера принимаются до 10 июня. Видео с предыдущего митапа в студийном качестве 4K уже выложены на нашем <a href="https://www.youtube.com/@EvroneDevelopment" rel=" noopener" target="_blank">YouTube-канале</a>.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://meetups.evrone.ru/python-meetup-online-3?utm_source=mail&amp;utm_medium=digest&amp;utm_campaign=python_digest_4_2023https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-3?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_4_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_4_2023" rel=" noopener" target="_blank">Подробнее</a></p> Fri, 07 Apr 2023 11:17:39 +0000 Evrone digest /20230407 Опаснее, быстрее, умнее https://digest.evrone.ru/20230309 <img src="/sites/default/files/styles/card_m/public/2023-03/image1_0.png?itok=ZtlylEs-" width="960" height="540" alt="Опаснее, быстрее, умнее" loading="lazy" typeof="Image" /> <br /> <p>Атаки на PyPI набирают обороты, Google пытается приучить сообщество к своему стайлгайду, линтер Ruff бьёт рекорды скорости, а генеративные сети продолжают задавать тренды. Всё это вы найдёте в нашем мартовском Python-дайджесте. Поехали!</p> <h2>Ещё одна серия атак на PyPi</h2> <p>Американская компания Phylum специализируется на безопасности цепочек поставок. Их команда исследователей и программистов разработала автоматизированную платформу, постоянно отслеживающую необычные публикации на PyPI. 23 февраля 2023 года эта система <a href="https://blog.phylum.io/phylum-discovers-another-attack-on-pypi" rel=" noopener" target="_blank">зафиксировала</a> аномальную активность. Количество опубликованных пакетов быстро увеличивалось с нескольких десятков до нескольких сотен. Новые пакеты публиковались каждые 4-8 секунд.</p> <p>Основная опасность каждого из таких пакетов состояла в том, что файл setup.py имел фрагмент, вызывающий команду Powershell. Сама команда была закодирована в Base64, чтобы не привлекать лишнего внимания. В расшифрованном виде эта команда выполняет веб-запрос в Dropbox, где лежит вредоносная нагрузка: дроппер на Rust. Но это лишь «верхушка айсберга» и первый этап заражения. Далее вредонос вызывает второй этап и сброс на диск нескольких бинарников. Каждый из них служит для маскировки под легитимные программы, если судить по названиям.</p> <p>Одно из названий весьма примечательно — Esquele.exe. Гугл-переводчик переводит esquele, как искажённое слово «скелет» (esqueleto) на испанском языке. Тоже самое определение дают и генеративные нейросети — ChatGPT и NotionAI. Весьма точное наименование для дроппера. (прим. автора)</p> <p>Детальный анализ механизма атаки позволил найти сходство с той, которую платформа зафиксировала в январе 2023 года. Тогда были опубликованы три библиотеки httpslib, colorslib и libhttps, в установочном коде которых был схожий порядок команд и маскировки, вроде переименования бинарника в WindowsCache.exe. Специалисты Phylum подозревают, что январская атака была лишь разминкой и тестированием эффективности. Так что советуем быть крайне осторожными при использовании PyPI, вероятнее всего атака продолжается и на момент публикации этого дайджеста.</p> <h2>Google Python Style Guide</h2> <p>Хороший код, как и хороший текст, начинается с правил и соглашений. Такой сборник может носить разные названия: coding standard, style guide, code style, programming style и тому подобные. Целью является единообразие, консистентность и отсутствие конфликтов между разными участниками команды. При этом новым разработчикам значительно проще адаптироваться к чтению кода, не упираясь в специфическое оформление. Общие стандарты развивают культуру разработки и улучшают комфорт чтения кода.</p> <p>Внутри отдельной компании создать внутреннее руководство по стилю не представляет сложности. Но как заставить разработчиков программного обеспечения с открытым исходным кодом придерживаться единого стиля? Кажется, корпорация Google решила, что имеет смысл поделиться с сообществом своим собственным <a href="https://google.github.io/styleguide/pyguide.html">стайлгайдом</a>. Мотив очевиден — чем больше независимых разработчиков будут следовать этому своду правил, тем меньше денег потратит корпорация на доработку их кода.</p> <p>Авторы документа составили его в виде списка советов. Их можно разделить на две категории: что стоит делать, а чего лучше избегать. Любители Vim останутся довольны, ведь им подготовили <a href="https://google.github.io/styleguide/google_python_style.vim" rel=" noopener" target="_blank">файл настроек</a>, помогающий корректно форматировать код. А вот для Emacs прекрасно подойдут и дефолтные настройки. Упоминается также использование инструментов автоматического форматирования <a href="https://github.com/psf/black" rel=" noopener" target="_blank">Black</a> и <a href="https://github.com/google/pyink" rel=" noopener" target="_blank">Pyink</a>.</p> <p>Отдельно отметим, что каждая рекомендация имеет чёткое обоснование и отвечает на вопрос «почему так, а не иначе?». Если какой-то совет может быть неоднозначным, то приводятся как плюсы, так и минусы решения. Большое внимание уделяется правильному комментированию кода, но при этом авторы советуют не пытаться описывать его. Что логично — люди, читающие ваш код, вполне могут разбираться в Python лучше вас. Здесь много советов из серии «Капитан Очевидность», но это всё равно полезно, ведь никто не может идеально знать все детали и нюансы.</p> <p>Такой стайлгайд — отличная возможность ознакомиться с концентрированным экстрактом опыта разработчиков Google и выработать своё персональное руководство по стилю.</p> <h2>Экстремально быстрый линтер ruff</h2> <p>Если загуглить, какой из линтеров стоит выбрать, то чаще всего предлагается два самых популярных: <a href="https://pypi.org/project/pylint/" rel=" noopener" target="_blank">Pylint</a> и <a href="https://pypi.org/project/flake8/" rel=" noopener" target="_blank">Flake8</a>. Оба этих инструмента работают отлично, но в больших проектах имеет значение другой фактор — скорость. В этом плане можно привести в пример экосистему вокруг JavaScript, где тулинг должен работать очень быстро. Использование быстрых языков, таких как Go и Rust, в <a href="https://swc.rs/" rel=" noopener" target="_blank">swc</a>, <a href="https://esbuild.github.io/" rel=" noopener" target="_blank">esbuild</a> и <a href="https://rome.tools/" rel=" noopener" target="_blank">Rome</a> позволило получить изначально высокую производительность. А раз такой подход сработал для JS, то вполне подойдёт и для Python.</p> <p><a href="https://github.com/charliermarsh/ruff" rel=" noopener" target="_blank">Ruff</a> — это Proof-of-Concept сразу двух идей:</p> <ol> <li aria-level="1">Реализованные на более производительных языках инструменты Python работают быстрее. </li> <li aria-level="1">Встроенные цепочки инструментов работают эффективнее их разрозненного набора.</li> </ol> <p>Всё это легко подтверждается бенчмарками. В качестве языка был выбран Rust и это действительно сделало линтер на 1-2 порядка быстрее конкурентов. Замеры на кодовой базе CPython показали, что Ruff работает молниеносно:</p> <p><img alt="Ruff " data-entity-type="file" data-entity-uuid="9e1de266-1366-49b1-a299-6d8ed35a7dc6" width="796" height="265" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/image2_9.png" /></p> <p>Доходит до смешного. Sebastián Ramírez (интервью с ним есть <a href="https://evrone.ru/blog/interviews/sebastian-ramirez-interview" rel=" noopener" target="_blank">на нашем сайте</a>), автор FastAPI, признался, что иногда добавляет преднамеренные ошибки в код. Так можно убедиться, что Ruff запущен и исправно функционирует. Вишенкой на торте может стать то, что несколько дней назад разработчики линтера Pylint <a href="https://github.com/PyCQA/pylint/blob/47cb11f4cb01a61f83d915d88e828f103a479980/pyproject.toml" rel=" noopener" target="_blank">начали переходить</a> с Flake8/Autoflake именно на Ruff. Будем следить за его развитием и обязательно расскажем о нём в будущих дайджестах.</p> <h2>Локальный аналог CoPilot</h2> <p><a href="https://github.com/features/copilot" rel=" noopener" target="_blank">CoPilot</a> обычно <a href="https://habr.com/ru/company/ispmanager/blog/683412/" rel=" noopener" target="_blank">критикуют</a> за архитектуру и стоимость. Это сервис, а значит ему нужно постоянное и качественное интернет-соединение. Кроме того, для большинства разработчиков его ценность не соответствует текущей стоимости, особенно, с учётом юридической неопределённости. Кому, например, будут принадлежать авторские права на сгенерированный код? Да и обучение генеративных нейросетей требует огромных датасетов, в которых вполне может обнаружиться чей-то проприетарный фрагмент кода.</p> <p>Выбор в пользу клиент-серверной архитектуры был очевиден. Современные нейросети требуют много вычислительных ресурсов, а это сопутствующие расходы на оборудование и электроэнергию. К тому же сам датасет надо где-то хранить. Ну а клиенту остаётся лишь посылать запросы по API и получать ответы.</p> <p>Но что, если всё-таки хочется получить локального AI-помощника на своей машине? У модели OpenAI Codex, на которой построен CoPilot, есть бесплатный конкурент — <a href="https://github.com/salesforce/CodeGen" rel=" noopener" target="_blank">CodeGen</a>. Он представляет собой 4 предварительно обученных модели с разным количеством параметров: 350M, 2B, 6B, 16B. Если у вас под рукой компьютер с хорошей видеокартой на 16 Гб видеопамяти, то можно выбрать вариант с 2B. На меньшем количестве VRAM можно попробовать вариант 350M. Совсем недавно о своём опыте использования CodeGen <a href="https://habr.com/ru/post/720228/" rel=" noopener" target="_blank">рассказал</a> один из пользователей Хабра.</p> <p>В обозримом будущем можно обратить внимание на хитрую утилиту <a href="https://github.com/FMInference/FlexGen" rel=" noopener" target="_blank">FlexGen</a>, позволяющую запускать большие языковые модели на системах с недостаточным количеством видеопамяти. Их дорожная карта указывает, что в будущем разработчики добавят поддержку моделей CodeGen, а также ускорителей ANE (Apple Neural Engine), встроенных в процессоры Apple Silicone.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>29 марта 2023</p> <p>Совсем скоро состоится весенний Python Meetup. Вас ждут три отличных доклада:</p> <ul> <li> <p>Андрей Скиба из Uchi.ru поделится опытом работы со сложными метриками. Вместо дорогих коммерческих решений они пошли по пути написания собственной легковесной системы.</p> </li> <li> <p>Шарыпов Алексей из VK раскроет подробности создания небольшого проекта на FastAPI c использованием Poetry от начала до production-ready образа. Все вкусные подробности, вроде настройки линтеров и тестов, присутствуют.</p> </li> <li> <p>Алексей Каньков из Revizto посвятит доклад функциональному программированию на Python. Эта парадигма не только помогает управлять параллелизмом, но и упрощает тестирование, а также сводит к минимуму побочные эффекты.</p> </li> </ul> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-2?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_3_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_3_2023" rel=" noopener" target="_blank">Подробнее</a></p> Thu, 09 Mar 2023 14:43:41 +0000 Evrone digest /20230309 Управление зависимостями и устройствами https://digest.evrone.ru/20230206 <img src="/sites/default/files/styles/card_m/public/2023-02/image1.png?itok=XGHZky5T" width="960" height="540" alt="Управление зависимостями и устройствами " loading="lazy" typeof="Image" /> <br /> <p>Сегодня разберёмся с консервативным подходом к управлению зависимостями, порулим сетевыми устройствами Mikrotik и погрузимся в историю создания CircuitPython для программирования микроконтроллеров. Приятного чтения!</p> <h2>Скучный Python — зависимости</h2> <p>В мае 2022 года разработчик из Калифорнии James Bennett рассказал свой подход к управлению зависимостями в статье <a href="https://www.b-list.org/weblog/2022/may/13/boring-python-dependencies/" rel=" noopener" target="_blank">«Boring Python: dependency management»</a>. В его представлении термин «скучный Python» это не характеристика языка, а набор рекомендаций по уменьшению количества багов, «нескучных сюрпризов». Полностью от них избавиться нереально. Можно лишь снизить их число, убрав потенциальные источники ошибок.</p> <p>Во многом его советы сводятся к исключению экспериментов и использованию стандартного инструментария там, где это возможно. Штатная экосистема пакетов Python насчитывает три инструмента: <a href="https://pypi.org/project/setuptools/" rel=" noopener" target="_blank">setuptools</a>, <a href="https://pypi.org/project/pip/" rel=" noopener" target="_blank">pip</a> и <a href="https://docs.python.org/3/library/venv.html" rel=" noopener" target="_blank">venv</a>. Они неспешно развивались более 10 лет и доказали свою надёжность. По мнению автора, не стоит пытаться искать и использовать альтернативы, поскольку в дальнейшем это станет источником проблем.</p> <p>Если речь заходит о системе управления пакетами pip, то имеет смысл задуматься, как передавать туда имена устанавливаемых пакетов. Это может быть или список имён в командной строке или сформированный файл(ы) с требованиями. Второй вариант удобнее и помогает формированию переносимой среды.</p> <p>Зависимости часто тянут за собой другие зависимости, явно не указанные в файле требований. Их еще называют «транзитивными» зависимостями. Разработчику стоит взять под контроль всё «дерево» зависимостей. Для этого существует пакет <a href="https://pypi.org/project/pip-tools/" rel=" noopener" target="_blank">pip-tools</a>. Помимо поддержания зависимостей в актуальном состоянии, он позволяет обеспечить предсказуемость и детерминированность сборки. Также не стоит забывать о безопасности — <a href="https://pip.pypa.io/en/stable/cli/pip_install/#hash-checking-mode" rel=" noopener" target="_blank">проверка хэша</a> существенно уменьшит риск проникновения вредоносных пакетов в проект, что в последние месяцы особенно <a href="https://digest.evrone.ru/20230110" rel=" noopener" target="_blank">актуально</a>.</p> <p>Не пренебрегайте виртуальными средами, «virtual environments». Это гарантирует изоляцию интерпретатора Python и всех установленных пакетов. Таким образом можно иметь сразу несколько независимых друг от друга сред разработки. Всё это путь к максимально воспроизводимой и согласованной среде. Её будет легко перенести и развернуть на любой инфраструктуре.</p> <p>В случае внезапного изменения зависимостей установка завершится неудачей по причине несоответствия хэшей. Вишенка на торте — минимум забот и потенциальных конфликтов с установленным на конечной системе интерпретатором Python и нужных ему пакетов.</p> <h2>Paramiko для MikroTik</h2> <p>Латвийская компания MikroTik хорошо известна всем сетевым инженерам. Устройства, разрабатываемые этой компанией, работают как дома и в небольших офисах, так и в крупных дата-центрах. Если говорить о маршрутизаторах, то они работают на операционной системе RouterOS. Поддерживается множество способов управления — от консольного доступа через SSH/Telnet до использования <a href="https://wiki.mikrotik.com/wiki/Manual:Webfig" rel=" noopener" target="_blank">Webfig</a>/<a href="https://wiki.mikrotik.com/wiki/Winbox" rel=" noopener" target="_blank">WinBox</a>. Разработчикам также доступен вариант управления <a href="https://help.mikrotik.com/docs/display/ROS/API" rel=" noopener" target="_blank">через API</a>. Это позволяет создавать кастомные приложения, способные собирать показания с сетевых устройств и управлять ими.</p> <p>Сама MikroTik в качестве <a href="https://wiki.mikrotik.com/wiki/Manual:API_Python3" rel=" noopener" target="_blank">референса</a> указывает возможность взаимодействия без сторонних библиотек. Но для простых задач подойдёт и инструмент Paramiko, представляющий собой имплементацию протокола SSHv2. После <a href="https://www.paramiko.org/installing.html" rel=" noopener" target="_blank">установки</a> можно сразу накидать простой код, вроде такого:</p> <p> </p> import paramiko # Подключимся к маршрутизатору ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect("&lt;IP-ADDRESS&gt;", username="&lt;USERNAME&gt;", password="&lt;PASSWORD&gt;") # Для примера выполним команду вывода IP-адреса stdin, stdout, stderr = ssh.exec_command("/ip/address/print") # Выведем результат print(stdout.read().decode()) # Закроем SSH-соединение ssh.close() <p>Заменяем &lt;IP-ADDRESS&gt;, &lt;USERNAME&gt; и &lt;PASSWORD&gt; на действительные значения и можно тестировать. Это лишь самый примитивный пример применения.</p> <p>Сценарий использования в дата-центре может выглядеть следующим образом. Сетевое оборудование чаще всего учитывается в системе DCIM (Data center infrastructure management). Опытному разработчику ничего не стоит выгрузить реестр с оборудованием из DCIM, а затем выполнить выполнить нужные действия сразу на группе маршрутизаторов. Так, например, можно выполнить обновление программного обеспечения, бэкап или восстановление файлов конфигурации.</p> <h2>CircuitPython от Adafruit</h2> <p>Прошло 10 лет с того момента, как Эрнандо Барраган (Hernando Barragán) решил в качестве магистерской диссертации создать дешевую и простую среду для начального обучения программированию. Результатом стала платформа <a href="https://en.wikipedia.org/wiki/Wiring_(development_platform)" rel=" noopener" target="_blank">Wiring</a>, форк которой мы знаем под названием Arduino.</p> <p>С ростом популярности платформы Arduino стали появляться компании, разрабатывающие совместимые модули расширения. Эти модули значительно снижают порог входа в разработку, так как включают в себя всю необходимую обвязку. То есть пользователи не должны паять, а просто подключают модули и начинают программировать. Компании вроде Adafruit Industries предлагают сенсоры, дисплеи, драйверы для двигателей, а также другие модули расширения.</p> <p>Разработка качественного железа стала одним из факторов успеха. Но без создания приложений и формирования экосистемы компания вряд ли бы достигла текущих показателей. Инженеры Adafruit пошли дальше и решили ещё упростить программирование микроконтроллеров, сделав ставку на внедрение <a href="https://evrone.ru/technologies/python" rel=" noopener" target="_blank">Python</a>. Проблема была лишь в том, что применяемые чипы обладали весьма скромными характеристиками. Это значило, что поддерживать все фичи языка было бы нереальной задачей.</p> <p>Конечно, Adafruit не единственные, кому в голову пришла идея создать Python для микроконтроллеров. В 2013 году успешная краудфандинговая кампания австралийского разработчика Дэмиена Джорджа (Damien George) позволила создать такую версию, названную <a href="https://github.com/dpgeorge/micropython" rel=" noopener" target="_blank">MicroPython</a>. Adafruit решили не изобретать велосипед, а взять этот код за основу уже собственного продукта <a href="https://circuitpython.org/" rel=" noopener" target="_blank">CircuitPython</a>.</p> <p>Из оригинала были удалены прерывания и многопоточность. Параллелизм поддерживается весьма условно. Async/await доступны лишь на некоторых платах, а для решения типовых задач, вроде воспроизведения музыки, были созданы отдельные программные модули. Чтобы в результате жесткого сбоя пользователь не получил «кирпич», был добавлен специальный безопасный режим, позволяющий пропустить запуск пользовательского кода. Если приложение вызвало сбой, плата остается доступной.</p> <p>CircuitPython отлично <a href="https://docs.circuitpython.org/en/7.3.x/README.html" rel=" noopener" target="_blank">задокументирован</a>, поддерживает более 300 устройств и даёт возможность пробросить код на Python в «реальный мир». Если у вас завалялся <a href="https://circuitpython.org/downloads" rel=" noopener" target="_blank">поддерживаемый</a> микроконтроллер без дела, то в него можно вдохнуть жизнь с помощью любимого языка программирования.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>29 марта 2023</p> <p> </p> <p>Рады сообщить, что у нас запланирован весенний Python Meetup. Программа мероприятия формируется. Подать заявку на участие спикера можно до 10 марта. Детальная информация будет опубликована позже, следите за нашими новостями.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-2?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_2_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <p>Удаленка / Офис</p> <h3>Evrone </h3> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_2_2023" rel=" noopener" target="_blank">Подробнее</a></p> Mon, 06 Feb 2023 11:30:11 +0000 Evrone digest /20230206 Быть начеку https://digest.evrone.ru/20230110 <img src="/sites/default/files/styles/card_m/public/2023-01/python%201.png?itok=HpczS1mA" width="960" height="540" alt="Быть начеку" loading="lazy" typeof="Image" /> <br /> <p>В нашем сегодняшнем дайджесте вы узнаете, как при обычном использовании PyPI поймать зловред. Ещё мы расскажем о ресурсе, собравшем нетривиальные примеры кода, подведём итоги 2022 года для urllib3 и выясним, как добавить настоящей песочнице интерактивности.</p> <h2>Предновогодняя атака на PyTorch</h2> <p>Рождество и Новый год прекрасные праздники, но как раз в это время активизируются злоумышленники, рассчитывая на сниженное внимание и уменьшение контроля. Пока некоторые разработчики и DevOps-инженеры мысленно уже начинали открывать напитки и выбирать себе подарки, фреймворк <a href="https://pytorch.org/" rel=" noopener" target="_blank">PyTorch</a> подвергся атаке на цепочки поставок.</p> <p>Тот, кто спланировал атаку хорошо знал особенности PyPI. Вредоносный пакет torchtriton был загружен с тем же именем, которое использует PyTorch nightly. Система проиндексировала его и дала больший приоритет, чем легитимному пакету. Таким образом все, кто загрузил PyTorch-nightly в Linux через pip в период с 25 декабря 2022 г. по 30 декабря 2022 г., получили в нагрузку вредоносный бинарник triton. Зловред ворует данные и загружает на подконтрольный сервер. Такая атака была давным-давно предсказана и досконально описана в <a href="https://github.com/pypa/pip/issues/5045" rel=" noopener" target="_blank">Issue #5045</a> и <a href="https://github.com/pypa/pip/issues/8606" rel=" noopener" target="_blank">Issue #8606</a>. Но логика работы PyPI осталась неизменной.</p> <p>Чтобы проверить, был ли ваш сервер скомпрометирован, выполните команду:</p> python3 -c "import pathlib;import importlib.util;s=importlib.util.find_spec('triton'); affected=any(x.name == 'triton' for x in (pathlib.Path(s.submodule_search_locations[0] if s is not None else '/' ) / 'runtime').glob('*'));print('You are {}affected'.format('' if affected else 'not '))" <p>В блоге <a href="https://pytorch.org/blog/compromised-nightly-dependency/" rel=" noopener" target="_blank">PyTorch</a> указан хэш вредоносного бинарника и данные о его поведении:</p> SHA256(triton)= 2385b29489cd9e35f92c072780f903ae2e517ed422eae67246ae50a5cc738a0e <p>С того момента, как вредоносный код был обнаружен, пакет с «сюрпризом» загрузили примерно 3 тысячи раз. Но за то же время стабильный билд PyTorch загрузили 1.5 млн раз, значит, атака была не масштабной? Даже от такой скромной ущерб может быть существенным.</p> <p>Через некоторое время автор атаки, белый хакер, вышел на связь и принес свои извинения. <a href="https://www.bleepingcomputer.com/news/security/pytorch-discloses-malicious-dependency-chain-compromise-over-holidays/" rel=" noopener" target="_blank">Утверждается</a>, что он хотел лишь продемонстрировать уязвимость, а не нанести реальный ущерб. Тем не менее специалисты по безопасности советуют проверить инфраструктуру и сменить все скомпрометированные ключи доступа в случае обнаружения зловреда.</p> <h2>Не верь глазам своим</h2> <p>Профессия разработчика подразумевает непрерывное обучение, причём разными способами. Самым интересным будет разбирать поведение некоторых участков кода, которые ведут себя не так, как предполагается. Эта практика позволяет глубже заглянуть в язык и получить представление о работе кода.</p> <p>Помощником в этом может стать проект wtfpython, доступный как <a href="https://github.com/satwikkansal/wtfpython" rel=" noopener" target="_blank">на английском</a>, так и частично <a href="https://github.com/frontdevops/wtfpython" rel=" noopener" target="_blank">на русском</a> языке. Этот мануал даже доступен в виде устанавливаемого пакета PyPI:</p> $ pip install wtfpython -U $ wtfpython <p>В нём много интересных примеров, которые рекомендуется изучать, читая код и пытаясь предсказать результат его выполнения. А потом посмотреть на фрагменты вывода.</p> <p>Даже опытные разработчики удивятся результатам такой проверки знаний. Накопленный опыт вызывает эффект «замыливания глаз», знакомый любому техническому писателю или автору контента. Ещё и скрытые от внешних глаз механизмы языка могут вести себя необычно. Так что вы наверняка откроете для себя что-то новое и сможете взглянуть на код с другого ракурса.</p> <h2>В ожидании urllib3 v2</h2> <p>Стандартная библиотека Python хороша, но всё же лишена многих нужных функций. Если вам потребовалось использовать удобный и потокобезопасный HTTP-клиент, то скорее всего возьмёте <a href="https://urllib3.readthedocs.io/en/stable/" rel=" noopener" target="_blank">urllib3</a> или <a href="https://requests.readthedocs.io/en/stable/" rel=" noopener" target="_blank">requests</a>. Пакет urllib3 настолько популярен, что в сутки скачивается более 10 млн раз, а за 2022 год количество загрузок превысило 3 млрд раз.</p> <p>Такие крупные Open-source проекты требуют кропотливого труда множества людей. Делать это на чистом энтузиазме, разумеется, невозможно. Добровольные пожертвования на проект в 2022 году составили $26 615. Наибольший спонсорский взнос в размере $13 000 был сделан фондом Spotify FOSS. Из собранных средств $6 500 были распределены между мейнтейнерами и участниками сообщества. $18 827 остаются на открытом коллективном балансе проекта и будут использованы для будущего развития urllib3.</p> <p>В ноябре 2022 года вышел urllib3 v2.0.0a1. Кодовую базу оптимизировали для Python 3.7+, удалили поддержку старых версий. Полный список изменений есть в <a href="https://github.com/urllib3/urllib3/releases/tag/2.0.0a1" rel=" noopener" target="_blank">репозитории проекта</a> на GitHub.</p> <p>Важнейшей задачей при разработке второй версии было сохранение 99% обратной совместимости. Обновление не должно вызвать никаких проблем у большинства пользователей. Надеемся, что у разработчиков это получится и мы увидим релиз v2.0.0 в первой половине 2023 года.</p> <h2>Интерактивная карта на песке</h2> <p>Вернёмся на 13 лет назад. Microsoft представила Project Natal, более известный как Kinect. Революционный игровой контроллер, считывающий в трехмерном пространстве движения и позы игрока. В его основе два датчика глубины и цветная камера. Вместе они позволяют получать и изображения, и карты глубины. Первая версия контроллера обладала низкой точностью и разрешением, что существенно улучшилось в следующей версии. Увы, но добиться достаточной точности в играх так и не удалось, что и послужило причиной снятия с производства в 2017 году.</p> <p>Но это вовсе не поставило крест на альтернативном использовании Kinect. Что только не делали на его основе — от музыкального инструмента и диджейского пульта до 3D-сканера (что оказалось в 200 раз дешевле промышленного устройства). Там, где не требовалась высокая скорость движений, Kinect прекрасно справлялся с построением карт глубин и это привлекло к нему интерес множества разработчиков, в том числе и военных.</p> <p>Когда мы говорим слово «песочница», то чаще всего используем его в переносном смысле. Если объединить настоящую песочницу, проектор и Kinect, получится проект <a href="https://github.com/thomwolf/Magic-Sand" rel=" noopener" target="_blank">Magic-Sand</a>, настоящий бриллиант мира дополненной реальности. Его часто демонстрируют на выставках и публичных мероприятиях.</p> <p> </p> <img alt="Magic-Sand песочница на выставке CSEO Apollo-Artemis" data-entity-type="file" data-entity-uuid="b0c20eca-2272-44da-aa64-0b6c27917d5c" width="1999" height="1333" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/image1.jpg" /> Magic-Sand песочница на выставке <a href="https://www.spaceexploration.org.cy/?i=55#!/News">CSEO Apollo-Artemis</a> <p>Казалось бы, забавная игрушка, красивая демонстрация, не более. Но на её базе создали вполне серьёзную систему планирования с учётом особенностей рельефа. Проект CombatViewer объединяет опыт <a href="https://github.com/Caique-P/CombatViewer" rel=" noopener" target="_blank">Magic-Sand</a> со слоем карты, а также лазерной указкой для перетаскивания объектов.</p> <img alt="Демонстрация перемещения объектов по песочнице лазерной указкой" data-entity-type="file" data-entity-uuid="3f7245ea-eefc-4041-a93d-1c5d77327e83" width="632" height="345" loading="lazy" class="lazyload" data-src="/sites/default/files/inline-images/image3_1.gif" /> ​​​​Демонстрация перемещения объектов по песочнице лазерной указкой <p>В качестве стека использовался Python вместе с библиотекой машинного зрения OpenCV и интерфейсом на Tkinter. Автор проекта опубликовал <a href="https://medium.com/@caiqueponjjar/how-i-used-python-and-stood-out-in-my-mandatory-military-service-7b08c56b4ec8" rel=" noopener" target="_blank">небольшую статью</a> на Medium, а готовая версия в настоящий момент активно используется в Бразилии.</p> <h2 id="article_title_7">Митапы</h2> Онлайн <h3>Python meetup</h3> <p>29 марта 2023</p> <p>Рады сообщить, что у нас запланирован весенний Python Meetup. Программа мероприятия формируется. Детальная информация будет опубликована позже, следите за нашими новостями.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <p><a class="info-button" href="https://meetups.evrone.ru/python-meetup-online-2?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_1_2023" rel=" noopener" target="_blank">Регистрация</a></p> <h2 id="article_title_8">Вакансии</h2> <span>Удаленка / Офис</span> <h3>Evrone </h3> <p> </p> <p>Мы рады новым Python-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание как организовать разработку комфортно и эффективно. Присоединяйтесь!</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_digest_1_2023" rel=" noopener" target="_blank">Подробнее</a></p> Tue, 10 Jan 2023 07:08:24 +0000 Evrone digest /20230110 Многострадальный релиз https://digest.evrone.ru/20221208 <img src="/sites/default/files/styles/card_m/public/2022-12/image1_0.png?itok=nR_b0Kaa" width="960" height="540" alt="Многострадальный релиз" loading="lazy" typeof="Image" /> <br /> <p>Эпопея завершилась и Python 3.11 вышел в релиз. Предлагаем заварить чайку и похоливарить на тему стилей, принципов и нотаций именования переменных. На связи Evrone, мы рады говорить с вами на одном языке.</p> <h2>Ключевые изменения</h2> <p>Ещё не успел остыть свежеиспечённый релиз <a href="https://evrone.ru/technologies/python" rel=" noopener" target="_blank">Python</a>, как в чатах разработчиков посыпались шутки о том, что следующая версия должна называться Python NT Workstation. Но шутки-шутками, а Python 3.11 for Workgroups получился весьма интересным. Путь к релизу был тернистым и включал в себя 5 beta-версий и сдвиг срока релиза. Благо всё это позади, и мы можем взглянуть на результат.</p> <p>Эталонный интерпретатор CPython стал быстрее. Прирост составил от 10% до 60% по сравнению с предыдущей версией 3.10. В качестве средней цифры разработчики называют 25%. Публичные результаты бенчмарков <a href="https://github.com/faster-cpython/ideas#published-results" rel=" noopener" target="_blank">опубликованы</a> на Github. В качестве небольшого спойлера — там же вы найдёте и результаты альфа-версии 3.12.0a0.</p> <p>Добавили группировку и одновременное использование нескольких несвязанных исключений. Реализовано это с помощью типов <a href="https://docs.python.org/3.11/library/exceptions.html#ExceptionGroup" rel=" noopener" target="_blank">ExceptionGroup и BaseExceptionGroup</a>. Оператор except также получил <a href="https://docs.python.org/3.11/reference/compound_stmts.html#except-star" rel=" noopener" target="_blank">синтаксис</a>, позволяющий управлять этими группами. Вдобавок исключения теперь можно снабжать заметками через метод add_note().</p> <p>Стандартная библиотека пополнилась модулем для парсинга TOML-файлов <a href="https://docs.python.org/3.11/library/tomllib.html#module-tomllib" rel=" noopener" target="_blank">tomllib</a>. Этот формат появился давно, ещё 9 лет назад, и с тех пор хорошо зарекомендовал себя для хранения настроек в различных приложениях. Разумеется, это не единственные изменения, но наиболее значимые. Познакомиться с оставшимися можно в <a href="https://docs.python.org/3.11/whatsnew/3.11.html#" rel=" noopener" target="_blank">официальной документации</a>.</p> <h2>EAFP против LBYL</h2> <p>Зубодробительные аббревиатуры наше всё. Но если WYSIWYG знает каждый, то аббревиатуры EAFP и LBYL многие слышат впервые. Первое переводится, как Easier to Ask for Forgiveness than Permission (проще просить прощения, чем разрешения). Применительно к программированию этот принцип означает, что можно писать любой код и ожидать, что он будет работать как положено. Если на каком-то этапе возникает исключение, то его нужно обработать соответствующим образом.</p> <p>Полной противоположностью EAFP является принцип LBYL — Look Before You Leap (посмотри, прежде чем прыгать). Используя этот принцип, следует вначале удостовериться, что решение сработает и лишь потом писать код. Такой подход более применим для других языков программирования, таких как C/C++, где возникновение исключения — ситуация действительно исключительная. Для Python она таковой не будет.</p> <p>Прекрасная демонстрация есть на <a href="https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python" rel=" noopener" target="_blank">StackOverflow</a>.</p> <p>EAFP:</p> try: x = my_dict["key"] except KeyError: # handle missing key <p>Мы пробуем присвоить переменной значение ключа, выполнив поиск в словаре. Если что-то пошло не так — выбрасываем исключение. Ключ ищется только один раз.</p> <p>LBYL:</p> if "key" in my_dict: x = my_dict["key"] else: # handle missing key <p>А тут получается мы ищем ключ дважды. Первый раз, чтобы сработало условие и второй раз для присвоения переменной. Вариант рабочий, но менее читабельный.</p> <p>Если <a href="https://devblogs.microsoft.com/python/idiomatic-python-eafp-versus-lbyl/" rel=" noopener" target="_blank">начать сравнивать</a> оба этих принципа, то может возникнуть ощущение, что EAFP может обойтись «слишком дорого» и снизит производительность. Отчасти это правда, но каждая новая реализация интерпретатора «снижает стоимость» использования исключений.</p> <p>В сухом остатке можно сделать простой вывод о том, что EAFP отлично подходит для Python. Разумеется, это не исключает того, что выбор остаётся исключительно за разработчиком.</p> <h2>Нотации именования</h2> <p>В холиварах про имена переменных отметилось не одно поколение разработчиков. Все хотят единое правило, но каждый — своё. Давайте взглянем на наиболее популярные нотации.</p> <ul> <li>Pascal case требует имена переменных начинать с заглавной буквы, например, Name. Если имя содержит несколько слов, то все они должны начинаться с заглавной буквы. Пример — FirstName.</li> <li>Camel case (верблюжья нотация) очень похожа на Pascal case, но есть одно кардинальное отличие. Односложные имена начинаются со строчной буквы, например, name. Если имя содержит несколько слов, то первая буква строчная, а все последующие заглавные. Пример — firstName.</li> <li>Snake case (змеиная нотация). Все имена начинаются со строчных букв. В качестве разделителя используется нижний пробел. Пример — first_name.</li> <li>Kebab case (шашлычная нотация) такая же, как и Snake case, но в качестве разделителя используется дефис. Пример — first-name.</li> <li>Hungarian notation (венгерская нотация) отличается от всех. Имя любой переменной предваряется заранее определёнными префиксами. Строгих правил у этой нотации нет — префикс может быть из одного или нескольких символов. При этом она может мимикрировать под другие нотации. Примеры — pFirstName, pfirst_name, pfirst-name.</li> </ul> <p>Это наиболее часто употребляемые нотации, в жизни их гораздо больше. И несмотря на то, что можно выбрать любую, для каждого языка предусмотрена предпочтительная нотация.</p> <p>В Python — это Snake Case для функций и переменных, а также Pascal Case для классов, что зафиксировано в <a href="https://peps.python.org/pep-0008" rel=" noopener" target="_blank">PEP8</a>. Это руководство по стилю позволяет избежать множества неприятных ситуаций и рекомендуется к соблюдению авторами языка.</p> <h2>Интересно посмотреть</h2> <p>Пропустили наш предыдущий Python-митап? Не беда! Все доклады есть на нашем <a href="https://www.youtube.com/c/EvroneDevelopment" rel=" noopener" target="_blank">YouTube-канале</a> в 4K.</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone" rel=" noopener" target="_blank">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <h2 id="article_title_8">Вакансии</h2> <span>Удаленка / Офис</span> <h3>Evrone </h3> <p>Мы открыты для новых Python-разработчиков. В Evrone можно работать удалённо с первого дня, мы поддерживаем и оплачиваем участие в Open-source проектах и выступления на конференциях, а расти в грейдах можно с помощью честной системы проверки навыков и менторства.</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_12_22" rel=" noopener" target="_blank">Подробнее</a></p> Thu, 08 Dec 2022 13:58:50 +0000 Evrone digest /20221208 Польза и вред кастомизации https://digest.evrone.ru/20221109 <img src="/sites/default/files/styles/card_m/public/2022-11/python_11.png?itok=k68ObBtd" width="960" height="540" alt="Польза и вред кастомизации" loading="lazy" typeof="Image" /> <br /> <p>В Python есть кастомизация. Собственные рингтоны и заставки как владельцы первых смартфонов не установите, но возможности есть. Но стоит ли игра свеч? Об этом и не только в нашем ноябрьском дайджесте.</p> <h2>Custom exceptions</h2> <p>Задумайтесь — а нужны ли вообще пользовательские исключения? С одной стороны, в Python есть обилие встроенных исключений «‎на все случаи жизни». А с другой, хорошим вариантом будет говорить, где конкретно ошибка в приложении, а не просто указывать на большой кусок кода.</p> <p>Не будем вдаваться в крайности, можно найти баланс между использованием обоих типов исключений и извлечь из этого пользу.</p> <p>Создать пользовательское исключение легко — объявляем класс, являющийся наследником от встроенного Exception.</p> &gt;&gt;&gt; class PredictionError(Exception): ... pass <p>Вместо pass можно использовать эллипсис, о котором мы писали <a href="https://digest.evrone.ru/20221010#article_title_4" rel=" noopener" target="_blank">в предыдущем дайджесте</a> или заменить полностью строкой документации. Имена исключениям важно давать максимально информативные и соблюдать нотацию CamelCase. Чем подробнее будет имя исключения, тем проще его будет воспринимать в коде.</p> <p>Не забывайте, что для имён классов исключений в конце используется слово Error. Это немного смущает, ведь исключения и ошибки — две разные сущности, создаваемые с разными целями. В некоторых случаях исключение может быть тождественно ошибке. Реально же исключение стоит вызывать лишь при возникновении исключительной ситуации, она не обязательно будет ошибочной.</p> <p>Пара важных моментов про вызов пользовательских исключений. Это либо делается вместе с проверкой какого-либо условия, либо перехватом встроенного исключения. Наиболее полезен второй вариант. Если включить в него сообщение, больше относящееся к конкретным особенностям приложения, то финально мы получим два блока информации. Один блок о содержимом стека, а другой с дополнительной информацией про то, что именно случилось с приложением.</p> <p>Разумеется, это лишь идеи, конкретное воплощение которых раскрывает статья <a href="https://towardsdatascience.com/should-we-use-custom-exceptions-in-python-b4b4bca474ac" rel=" noopener" target="_blank">Should we use custom exceptions in Python?</a>. Там есть примеры кода и детальное объяснение каждого из описываемых решений.</p> <h2>Собственные расширения Python</h2> <p>Продолжаем тему кастомизации, сейчас расскажем о расширениях.</p> <p>Иногда данных значительно больше, чем можно обработать имеющимися ресурсами. С одной стороны, можно отдать это на откуп инфраструктуры, благо современные облака легко масштабируются. Но вот с другой стороны, можно попробовать ускорить работу кода за счёт написания собственных расширений на других языках, таких как <a href="https://cython.org/" rel=" noopener" target="_blank">Cyphon</a> или <a href="https://www.rust-lang.org/" rel=" noopener" target="_blank">Rust</a>.</p> <p>Почему это должно работать быстро? Python был создан на компромиссах между удобством и производительностью. Так что некоторые вещи в других языках могут работать в десятки раз быстрее. Это основная причина, по которой разработчики начинают писать собственные расширения и подключать их к Python.</p> <p>Нет, не стоит прямо сейчас открывать любимую IDE и переписывать всё, что можно и нельзя. Вначале оцените, насколько оригинальный код эффективен. Возможно лезть в дебри не потребуется и вы обнаружите, что получить прирост скорости можно простой оптимизацией и последующим рефакторингом. И лишь не найдя таких вариантов, стоит обратить внимание на написание собственного расширения.</p> <p>Это ведь тоже компромисс. Если делать расширение на Rust, то придётся смириться с тем, что у него более сложный синтаксис и статическая типизация. Если возьмёте Cython с привычной динамической типизацией и пропустите какой-либо тип переменной, то производительность может резко упасть, а в чём тогда смысл?</p> <p>Тем не менее, когда вы точно понимаете где находится bottleneck вашего кода, усилия по написанию собственного расширения будут оправданы. Это может улучшить производительность. Напоследок советуем прочитать туториал от RealPython про <a href="https://realpython.com/build-python-c-extension-module/" rel=" noopener" target="_blank">создание собственных расширений на С</a> и статью <a href="https://towardsdatascience.com/nine-rules-for-writing-python-extensions-in-rust-d35ea3a4ec29" rel=" noopener" target="_blank">Nine Rules for Writing Python Extensions in Rust</a>.</p> <h2>Распознавание речи с OpenAI Whisper</h2> <p>Американская компания OpenAI, одним из основателей которой является Илон Маск, в конце сентября этого года сделала важный вклад в развитие открытого программного обеспечения. они выложили в общий доступ система распознавания речи (ASR) Whisper. Сердце системы — натренированная на 680 000 часов речи нейронная сеть, которая по словам разработчиков приблизилась к человеческому уровню распознавания.</p> <p>Разумеется, нейронная сеть «‎заточена» на английский язык. Но это вовсе не значит, что она бесполезна для распознавания русского языка. Некоторые исследовательские проекты уже провели <a href="https://blog.gdeltproject.org/experiments-applying-openais-whisper-asr-to-russian-television-news/" rel=" noopener" target="_blank">эксперименты</a> на примере видеозаписей с российского ТВ.</p> <p>Эта нейронная сеть содержит 1.6 миллиарда параметров и способна выполнять перевод с 97 языков мира. Вместе с качественными и специальным образом подготовленными данными для обучения, разработчики задействовали приличное количество зашумлённых и не слишком качественных записей. В итоге это позволило существенно улучшить показатели нейросети.</p> <p>Такая система отлично подойдёт для получения расшифровки подкастов, докладов и конференций. Её можно применять в качестве основы для создания новых приложений с распознаванием речи, систем «‎умный дом» и интерактивных голосовых меню (IVR).</p> <h2>JIT-компилятор для Numpy</h2> <p>В наших дайджестах мы затрагивали тему JIT-компиляторов для Python, таких как <a href="https://digest.evrone.ru/20220310#article_title_4https://digest.evrone.ru/20220310#article_title_4" rel=" noopener" target="_blank">Pyjion</a>. Сегодня расскажем ещё об одном инструменте, позволяющем значительно ускорить обработку данных библиотекой NumPy. Это JIT-компилятор <a href="https://numba.pydata.org/" rel=" noopener" target="_blank">Numba</a>, разрабатываемый при поддержке гигантов Intel, AMD и NVIDIA.</p> <p>Основная идея — выполнять преобразование отдельных функций, написанных на  Python, в быстрый и оптимизированный машинный код с помощью <a href="https://llvm.org/" rel=" noopener" target="_blank">LLVM</a>. При этом разработчику не надо особо задумываться — достаточно обернуть нужную функцию декоратором, а Numba сделает всю остальную работу.</p> <p>Если же кода много и делать в этом случае ручное декорирование долго, можно воспользоваться автоматическим <a href="https://numba.readthedocs.io/en/stable/user/jit-module.html" rel=" noopener" target="_blank">декоратором</a>. Все подлежащие ускорению функции будут собраны в единый модуль и к ним будет автоматически применён jit-декоратор. Также почитайте прекрасный <a href="https://numba.readthedocs.io/en/stable/user/5minguide.html" rel=" noopener" target="_blank">5-минутный гайд</a>, как быстро начать применять Numba в своём проекте и какие режимы работы стоит использовать. </p> <p>Если же слегка поработать над кодом, можно добиться ещё лучшей производительности за счёт использования SIMD-векторизации и многопоточности. Первое улучшает взаимодействие с железом, автоматически определяя какие расширения стандартного набора команд есть в используемом процессоре. Второе улучшает работу кода на нескольких ядрах и упрощает запись параллельных циклов.</p> <p>Отдельно отметим, что Numba позволяет задействовать технологию CUDA и исполнять разогнанный код непосредственно на <a href="https://numba.readthedocs.io/en/stable/cuda/index.html" rel=" noopener" target="_blank">графических процессорах Nvidia</a>. При правильном применении это сделает ваш Python-код потрясающе быстрым.</p> <h2>Интересно посмотреть</h2> <p>Пропустили наш предыдущий Python-митап? Не беда! Все доклады есть на нашем <a href="https://www.youtube.com/c/EvroneDevelopment" rel=" noopener" target="_blank">YouTube-канале</a> в 4K.</p> <p>Алексей Шарыпов из VK рассказал, как они писали сервис для тестирования «‎черного ящика» (приложения без тестов и документации), написанном на малоизвестном языке:</p> <p>Савостьянов Дмитрий из Nordcurrent поделился опытом работы с необычным контентом, а именно записями игры в Dota 2. Как парсить реплеи матчей и записи стримов на YouTube и находить хайлайты при помощи специально обученных нейросетей BERT и TrOCR:</p> <p>Денис Аникин из Райффайзенбанка разложил по полочкам мысли о том, куда движется Python. Когда и зачем он ускоряется, NoGIL, Сinder и прочих нововведениях:</p> <p>Теперь следить за митапами Evrone стало удобнее. В Telegram-канале <a href="https://t.me/meetups_evrone">Evrone meetups</a> мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите <a href="https://t.me/andrew_aquariuss" rel=" noopener" target="_blank">@andrew_aquariuss</a>, чтобы узнать подробности.</p> <h2 id="article_title_8">Вакансии</h2> <span>Удаленка / Офис</span> <h3>Evrone </h3> <p>Мы открыты для новых Python-разработчиков. В Evrone можно работать удалённо с первого дня, мы поддерживаем и оплачиваем участие в Open-source проектах и выступления на конференциях, а расти в грейдах можно с помощью честной системы проверки навыков и менторства.</p> <p><a class="info-button" href="https://jobs.evrone.ru/?utm_source=digest_site&amp;utm_medium=transition&amp;utm_campaign=python_11_22" rel=" noopener" target="_blank">Подробнее</a></p> Wed, 09 Nov 2022 12:38:09 +0000 Evrone digest /20221109