Slide 1

Slide 1 text

Евгений Блинов Руководитель команды интеграции робототехнических решений Расширяем возможности стандартной библиотеки

Slide 2

Slide 2 text

Обо мне Работаю тимлидом в команде интеграции робототехнических решений Yandex Robotics Обожаю Python и регулярно на нем пишу. В свободное время делаю опенсорс Telegram: @blinof GitHub: github.com/pomponchik LinkedIn: linkedin.com/in/pomponchik Личный сайт: pomponchik.org

Slide 3

Slide 3 text

Штош

Slide 4

Slide 4 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности

Slide 5

Slide 5 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности ● Отдельные компоненты СБ могли устареть

Slide 6

Slide 6 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности ● Отдельные компоненты СБ могли устареть ● Создатели СБ могли что-то не предусмотреть

Slide 7

Slide 7 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности ● Отдельные компоненты СБ могли устареть ● Создатели СБ могли что-то не предусмотреть ● Вы добавляете поддержку новой ОС (пример: shlex -> mslex)

Slide 8

Slide 8 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности ● Отдельные компоненты СБ могли устареть ● Создатели СБ могли что-то не предусмотреть ● Вы добавляете поддержку новой ОС (пример: shlex -> mslex) ● Вы хотите все ускорить (asyncio loop -> uvloop, json -> ujson)

Slide 9

Slide 9 text

Зачем вообще нужно дополнять стандартную библиотеку? ● У вас могут быть специфические потребности ● Отдельные компоненты СБ могли устареть ● Создатели СБ могли что-то не предусмотреть ● Вы добавляете поддержку новой ОС (пример: shlex -> mslex) ● Вы хотите все ускорить (asyncio loop -> uvloop, json -> ujson) ● Вы переписываете все, что есть в питоне, на раст

Slide 10

Slide 10 text

Это не безрисковая история ● Привязка к стандартам – не панацея: ○ Непопулярные либы регулярно выпиливаются (см. PEP 594 и др.) ○ Стандарты консервируют неудачные решения ○ Стандарты могут конфликтовать (например, PEP-8 против java-style библиотек вроде logging)

Slide 11

Slide 11 text

Это не безрисковая история ● Привязка к стандартам – не панацея: ○ Непопулярные либы регулярно выпиливаются (см. PEP 594 и др.) ○ Стандарты консервируют неудачные решения ○ Стандарты могут конфликтовать (например, PEP-8 против java-style библиотек вроде logging) ● Старайтесь не привязываться к устаревшим компонентам: по крайней мере, к депрекейтнутым или нарушающим другие стандарты

Slide 12

Slide 12 text

Как вообще это делается? Есть несколько путей: ● Попробовать засунуть свой патч в СБ официально: долго, дорого, о**енно

Slide 13

Slide 13 text

Как вообще это делается? Есть несколько путей: ● Попробовать засунуть свой патч в СБ официально: долго, дорого, о**енно ● Написать свое расширение, повторяющее протоколы из СБ

Slide 14

Slide 14 text

Как вообще это делается? Есть несколько путей: ● Попробовать засунуть свой патч в СБ официально: долго, дорого, о**енно ● Написать свое расширение, повторяющее протоколы из СБ ● Сделать все “на глазок” (очень много расширений поступают именно так)

Slide 15

Slide 15 text

Как вообще это делается? Есть несколько путей: ● Попробовать засунуть свой патч в СБ официально: долго, дорого, о**енно ● Написать свое расширение, повторяющее протоколы из СБ ● Сделать все “на глазок” (очень много расширений поступают именно так) Я выбираю второй путь

Slide 16

Slide 16 text

Че за протоколы, кста? ● Протоколы доступны c Python 3.8 и позволяют с помощью тайп-чекера убедиться, что разные классы и использующий их код совместимы между собой

Slide 17

Slide 17 text

Че за протоколы, кста? ● Протоколы доступны c Python 3.8 и позволяют с помощью тайп-чекера убедиться, что разные классы и использующий их код совместимы между собой ● Кстати, стандартная библиотека более ранних питонов расширяется с помощью typing_extensions

Slide 18

Slide 18 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем

Slide 19

Slide 19 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол

Slide 20

Slide 20 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол 3. Убедиться, что нужные компоненты из СБ следуют нашему протоколу

Slide 21

Slide 21 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол 3. Убедиться, что нужные компоненты из СБ следуют нашему протоколу 4. Написать свои реализации протокола

Slide 22

Slide 22 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол 3. Убедиться, что нужные компоненты из СБ следуют нашему протоколу 4. Написать свои реализации протокола 5. Убедиться, что они следуют протоколу

Slide 23

Slide 23 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол 3. Убедиться, что нужные компоненты из СБ следуют нашему протоколу 4. Написать свои реализации протокола 5. Убедиться, что они следуют протоколу 6. Опционально: написать либу-враппер (shlex + mslex -> oslex)

Slide 24

Slide 24 text

Итак, каков путь? 1. Определиться с тем, что из СБ мы забираем 2. Описать протокол 3. Убедиться, что нужные компоненты из СБ следуют нашему протоколу 4. Написать свои реализации протокола 5. Убедиться, что они следуют протоколу 6. Опционально: написать либу-враппер (shlex + mslex -> oslex) 7. Адаптировать пользовательский код: ○ Реализовать DI для этого компонента и убедиться, что со СБ все работает ○ Подставить свой компонент вместо стандартного

Slide 25

Slide 25 text

Погнали по порядку

Slide 26

Slide 26 text

1. Огораживаем свою часть ● Забираем в протокол только реально нужное ● Стараемся не брать устаревшее / депрекейтнутое / спорное

Slide 27

Slide 27 text

2. Описываем протокол

Slide 28

Slide 28 text

3. Убеждаемся, что сама стандартная библиотека следует нашему протоколу ● Это можно делать через isinstance() внутри теста, если использовать декоратор @runtime_checkable для протокола

Slide 29

Slide 29 text

3. Убеждаемся, что сама стандартная библиотека следует нашему протоколу ● Это можно делать через isinstance() внутри теста, если использовать декоратор @runtime_checkable для протокола ● Также желательно натравить mypy на тесты, можно без –strict режима

Slide 30

Slide 30 text

3. Убеждаемся, что сама стандартная библиотека следует нашему протоколу ● Это можно делать через isinstance() внутри теста, если использовать декоратор @runtime_checkable для протокола ● Также желательно натравить mypy на тесты, можно без –strict режима ● Стандартная библиотека меняется, не забываем про matrix с разными версиями питона

Slide 31

Slide 31 text

4. Написать свои реализации протокола ● Наследоваться не обязательно (и даже не желательно, а то isinstance() может начать врать)

Slide 32

Slide 32 text

4. Написать свои реализации протокола ● Наследоваться не обязательно (и даже не желательно, а то isinstance() может начать врать) ● Кстати, протокол можно расширять

Slide 33

Slide 33 text

4. Написать свои реализации протокола ● Наследоваться не обязательно (и даже не желательно, а то isinstance() может начать врать) ● Кстати, протокол можно расширять ● Если расширяете протокол, не забудьте указать в доке, что это именно расширение протокола, и как эта штука взаимодействует со СБ

Slide 34

Slide 34 text

4. Написать свои реализации протокола ● Наследоваться не обязательно (и даже не желательно, а то isinstance() может начать врать) ● Кстати, протокол можно расширять ● Если расширяете протокол, не забудьте указать в доке, что это именно расширение протокола, и как эта штука взаимодействует со СБ ● Кстати, протоколы нельзя использовать совместно с абстрактными классами

Slide 35

Slide 35 text

5. Убедиться, что собственные реализации протокола следуют ему Здесь все аналогично проверке самой стандартной библиотеки

Slide 36

Slide 36 text

6. Опционально: написать либу-враппер ● Актуально для ОС-зависимых либ

Slide 37

Slide 37 text

6. Опционально: написать либу-враппер ● Актуально для ОС-зависимых либ ● Делаем опциональные импорты за клиента (с ними бывает много геморроя)

Slide 38

Slide 38 text

6. Опционально: написать либу-враппер ● Актуально для ОС-зависимых либ ● Делаем опциональные импорты за клиента (с ними бывает много геморроя) ● Содержимое либы-враппера будет выглядеть примерно так:

Slide 39

Slide 39 text

7. Адаптировать пользовательский код ● Убеждаемся, что пользовательский код покрыт тестами и тайпчекается

Slide 40

Slide 40 text

7. Адаптировать пользовательский код ● Убеждаемся, что пользовательский код покрыт тестами и тайпчекается ● Выносим нашу зависимость от СБ в DI: ○ https://en.wikipedia.org/wiki/Dependency_injection ○ DI-фреймворки тут не нужны!

Slide 41

Slide 41 text

7. Адаптировать пользовательский код ● Убеждаемся, что пользовательский код покрыт тестами и тайпчекается ● Выносим нашу зависимость от СБ в DI: ○ https://en.wikipedia.org/wiki/Dependency_injection ○ DI-фреймворки тут не нужны! ● Убеждаемся, что тесты и тайпчеки проходят

Slide 42

Slide 42 text

7. Адаптировать пользовательский код ● Убеждаемся, что пользовательский код покрыт тестами и тайпчекается ● Выносим нашу зависимость от СБ в DI: ○ https://en.wikipedia.org/wiki/Dependency_injection ○ DI-фреймворки тут не нужны! ● Убеждаемся, что тесты и тайпчеки проходят ● Подменяем реализацию со стандартнобиблиотечной на свою

Slide 43

Slide 43 text

7. Адаптировать пользовательский код ● Убеждаемся, что пользовательский код покрыт тестами и тайпчекается ● Выносим нашу зависимость от СБ в DI: ○ https://en.wikipedia.org/wiki/Dependency_injection ○ DI-фреймворки тут не нужны! ● Убеждаемся, что тесты и тайпчеки проходят ● Подменяем реализацию со стандартнобиблиотечной на свою ● Убеждаемся, что тесты и тайпчеки продолжают проходить

Slide 44

Slide 44 text

Погнали к примерам

Slide 45

Slide 45 text

emptylog

Slide 46

Slide 46 text

Задача: научиться тестировать логи ● Кто вообще пишет тесты на логирование? ● Я иногда пишу, это не очень-то удобно ● https://github.com/pomponchik/emptylog

Slide 47

Slide 47 text

Протокол логгера

Slide 48

Slide 48 text

Пустой логгер Ничего не делает.

Slide 49

Slide 49 text

Запоминающий логгер

Slide 50

Slide 50 text

Печатающий логгер

Slide 51

Slide 51 text

Расширение протокола: суммирование логгеров Очень полезно для тестов.

Slide 52

Slide 52 text

locklib

Slide 53

Slide 53 text

Пишем свои мьютексы ● Стандартная библиотека дает много примитивов синхронизации, но их никогда не бывает слишком много ● https://github.com/pomponchik/locklib

Slide 54

Slide 54 text

Протоколы локов

Slide 55

Slide 55 text

Лок без дедлоков

Slide 56

Slide 56 text

Закругляемся

Slide 57

Slide 57 text

Короче: ● Стандартную библиотеку можно расширять, но с осторожностью

Slide 58

Slide 58 text

Короче: ● Стандартную библиотеку можно расширять, но с осторожностью ● Наш путь – делать это через протоколы

Slide 59

Slide 59 text

Короче: ● Стандартную библиотеку можно расширять, но с осторожностью ● Наш путь – делать это через протоколы ● Протоколы нужно правильно очерчивать

Slide 60

Slide 60 text

Короче: ● Стандартную библиотеку можно расширять, но с осторожностью ● Наш путь – делать это через протоколы ● Протоколы нужно правильно очерчивать ● Обязательно прокладываем путь для встраивания в существующий код

Slide 61

Slide 61 text

Короче: ● Стандартную библиотеку можно расширять, но с осторожностью ● Наш путь – делать это через протоколы ● Протоколы нужно правильно очерчивать ● Обязательно прокладываем путь для встраивания в существующий код ● Мы увидели примеры: ○ emptylog ○ locklib

Slide 62

Slide 62 text

Евгений Блинов Руководитель команды интеграции робототехнических решений Наэтомвсе Ваши вопросы :)