PEP 649 и PEP 749: `__annotate__`
- https://peps.python.org/pep-0649
- https://peps.python.org/pep-0749
История
Одна из самых больших проблем Python – непродуманность аннотаций. Особенно их работа в рантайме.
В чем основная проблема?
В python3.10 хотели по-умолчанию включить
Но, не вышло. Такой подход ломает кучу кода, который резолвит аннотакции из строк в объекты. Пример:
Что будет в 3.14?
Взамен - еще с версии 3.11 - начали писать новый PEP про новый способ резолвить аннотации на основе дескрипторов. Меня даже в ПЕПе упомянули за вклад в данную фичу. Теперь компилятор не будет создавать
Теперь компилятор будет генерировать функцию
Теперь все аннотации стали ленивыми по-умолчанию.
А уже
В качестве
-
-
-
Как теперь получать аннотации?
Мы добавили модуль
А вот реализация
В следующих постах расскажу про модуль
Обсуждение: как вам данная фича? Будете использовать в своих проектах?
| Поддержать | YouTube | GitHub | Чат |
- https://peps.python.org/pep-0649
- https://peps.python.org/pep-0749
История
Одна из самых больших проблем Python – непродуманность аннотаций. Особенно их работа в рантайме.
В чем основная проблема?
class A:
@staticmethod
def build() -> A: # <- тут будет NameError, потому что в теле класса `A` имя `A` еще не определено
return A()
В python3.10 хотели по-умолчанию включить
from __future__ import annotations, что превращает все аннотации в строки на уровне компилятора:
static int
codegen_visit_annexpr(compiler *c, expr_ty annotation)
{
location loc = LOC(annotation);
ADDOP_LOAD_CONST_NEW(c, loc, _PyAST_ExprAsUnicode(annotation));
return SUCCESS;
}
Но, не вышло. Такой подход ломает кучу кода, который резолвит аннотакции из строк в объекты. Пример:
from __future__ import annotations
def some():
class A: ...
def build_a() -> A:
return A()
return build_a
import typing
typing.get_type_hints(some()) # NameError: A
Что будет в 3.14?
Взамен - еще с версии 3.11 - начали писать новый PEP про новый способ резолвить аннотации на основе дескрипторов. Меня даже в ПЕПе упомянули за вклад в данную фичу. Теперь компилятор не будет создавать
__annotations__ словарь во время компиляции, как раньше:
/* Every annotated class and module should have __annotations__. */
if (find_ann(stmts)) {
ADDOP(c, loc, SETUP_ANNOTATIONS);
}
Теперь компилятор будет генерировать функцию
__annotate__ в теле класса или функции, или модуля:
RETURN_IF_ERROR(codegen_nameop(c, loc, &_Py_ID(__annotate__), Store));
Теперь все аннотации стали ленивыми по-умолчанию.
А уже
__annotate__ будет возвращать правильные аннотации для установки в __annotations__, можно переопределить руками и проверить:
>>> class A:
... def __annotate__(format): # TODO: support all formats
... print(f'{format=}')
... return {'a': int}
>>> A.__annotations__
format=1
{'a': <class 'int'>}
В качестве
format могут быть 3 публичных вида:-
VALUE – дефолт, чтобы возвращать реальные типы-
FORWARDREF – чтобы возвращать annotationlib.ForwardRef для значений, которые "еще не определены", как в примере с классом A в самом начале-
STRING – для возвращения строк, как при __future__.annotations, смотри _StringifierКак теперь получать аннотации?
Мы добавили модуль
annotationlib, который теперь резолвит аннотации самым правильным способом. Пример:
>>> from typing import TypedDict
>>> class User(TypedDict):
... email: str
... friends: User
>>> from annotationlib import get_annotations, Format
>>> get_annotations(User) # <- VALUE is default
{'email': <class 'str'>, 'friends': <class '__main__.User'>}
>>> get_annotations(User, format=Format.FORWARDREF) # <- will be able to return VALUE in this case
{'email': <class 'str'>, 'friends': <class '__main__.User'>}
>>> get_annotations(User, format=Format.STRING)
{'email': 'str', 'friends': 'User'}
А вот реализация
__annotate__ для TypedDict. Очень хороший пример для вашего кода.В следующих постах расскажу про модуль
annotationlib, inspect.get_annotations, проблемы и сложности данной фичи. Подписывайся!Обсуждение: как вам данная фича? Будете использовать в своих проектах?
| Поддержать | YouTube | GitHub | Чат |
3👍119🔥48❤7👏2🤔2🤯2👎1😁1🤡1
PythoNN: видео с апрельского митапа
4 апреля прошел очередной #python митап в Нижнем Новгороде.
Было очень душевно и интересно.
Случился аншлаг! Пришло много нижегородцев и приехало очень много гостей: из Москвы, Питера, Кирова и других городов. Спасибо всем!
Было 4 крутых доклада:
- "Are you NATS?" – Гурбанов Михаил https://youtube.com/watch?v=atD3JVWurno
- "Почему исправление опечаток сложнее, чем кажется, и как мы с этим српавляемся" – Дмитрий Бровкин https://youtube.com/watch?v=9HRBwwaMIfA
- "Современный web с современными темплейтами" – Алексей Гончарук https://youtube.com/watch?v=lN3Pz_hUCio
- "Демистификация PostgreSQL-индексов" – Алексей Голобурдин https://youtube.com/watch?v=6kVGSLdj28k
А потом мы сидели в баре до 5 утра.
Что улучшить?
- Первый раз записывал на StreamYard, сделал плохую композицию слайдов и видео докладчика, исправим в следующий раз. Прикрепил все слайды в описании докладов – чтобы была возможность все прочитать и скопировать код
- Поработаем над звуком, сейчас он немного прыгал
Хотите присоединиться?
- Если хотите сделать доклад, пишите мне в личку – лично учу новичков выступать и делать слайды, полная свобода в выборе темы
- Если хотите просто послушать – следите за анонсами в чате и подписывайтесь на мой канал с записями
У нас в Нижнем – просто офигенно, всех ждем в гости! 🌆
| Поддержать | YouTube | GitHub | Чат |
4 апреля прошел очередной #python митап в Нижнем Новгороде.
Было очень душевно и интересно.
Случился аншлаг! Пришло много нижегородцев и приехало очень много гостей: из Москвы, Питера, Кирова и других городов. Спасибо всем!
Было 4 крутых доклада:
- "Are you NATS?" – Гурбанов Михаил https://youtube.com/watch?v=atD3JVWurno
- "Почему исправление опечаток сложнее, чем кажется, и как мы с этим српавляемся" – Дмитрий Бровкин https://youtube.com/watch?v=9HRBwwaMIfA
- "Современный web с современными темплейтами" – Алексей Гончарук https://youtube.com/watch?v=lN3Pz_hUCio
- "Демистификация PostgreSQL-индексов" – Алексей Голобурдин https://youtube.com/watch?v=6kVGSLdj28k
А потом мы сидели в баре до 5 утра.
Что улучшить?
- Первый раз записывал на StreamYard, сделал плохую композицию слайдов и видео докладчика, исправим в следующий раз. Прикрепил все слайды в описании докладов – чтобы была возможность все прочитать и скопировать код
- Поработаем над звуком, сейчас он немного прыгал
Хотите присоединиться?
- Если хотите сделать доклад, пишите мне в личку – лично учу новичков выступать и делать слайды, полная свобода в выборе темы
- Если хотите просто послушать – следите за анонсами в чате и подписывайтесь на мой канал с записями
У нас в Нижнем – просто офигенно, всех ждем в гости! 🌆
| Поддержать | YouTube | GitHub | Чат |
9🔥71👍29❤5👏1😁1🤩1
Сложности запуска Docker в CI
Когда я писал прошлый пост про работу CI в GitVerse, я получил несколько вопросов относительно: а как работает Docker-in-Docker (DinD) в таком CI? Я спросил ребят, как они планируют реализовать данную фичу в ближайшем будущем. Ответ получился очень интересным.
Со стороны задача "запустить DinD в публичном CI" не выглядит как-то архи-сложно. Однако, на деле как всегда есть нюансы.
Какие вообще есть варианты запуска DinD?
1. Можно взять docker:dind и прокинуть ему
Вот пример, насколько просто сбежать из такого контейнера (в самом простом случае):
Тут – просто вопиющий случай, который делает неправильно буквально все: выставляет
2. Можно взять
Я подготовил пример такой сборки: https://gitverse.ru/sobolevn/dind-demo
3. Можно запускать контейнеры в изолированной виртуалке, которая будет быстро стартовать, работать и умирать. 0 рисков, никаких общих сокетов и возможности сбежать
GitHub и Packer
GitHub пошел по третьему пути. Когда мы указываем в actions:
То происходит следующее:
- GitHub берет образ виртуалки ubuntu-latest из заранее подготовленных
- Быстро разворачиваем готовый образ при помощи Instant Restore / InPlace Restore из Azure
- GitHub запускает контейнер с
Но, внутри образов есть не только docker, там есть всё. Образ ubuntu весит 18GB 🫠
Но есть и минимальные виртуалки без всего. Собираются они при помощи packer.
Планы
GitVerse прямо сейчас разрабатывают что-то очень похожее. В планах:
- Разные ОС: разные linux, macos, windows
- Разные архитектуры: x86_64, arm
Кажется, что такой путь – очень удобный. Быстро, надежно, кастомизируемо.
Подпишись на их канал @gitversenews, чтобы быть в курсе всех новостей. Поддержка заинтересованных в развитии опенсорса продуктов и компаний, таких как GitVerse, помогает мне бесплатно делиться контентом с вами. Спасибо им большое за поддержку и помощь в подготовке поста.
Реклама. АО «СберТех»
18+
Когда я писал прошлый пост про работу CI в GitVerse, я получил несколько вопросов относительно: а как работает Docker-in-Docker (DinD) в таком CI? Я спросил ребят, как они планируют реализовать данную фичу в ближайшем будущем. Ответ получился очень интересным.
Со стороны задача "запустить DinD в публичном CI" не выглядит как-то архи-сложно. Однако, на деле как всегда есть нюансы.
Какие вообще есть варианты запуска DinD?
1. Можно взять docker:dind и прокинуть ему
docker.sock, а затем получить побег из курятника, и наблюдать, как пользователи получают полный доступ к машине, где гоняются другие сборки других проектов (с секретами, конечно же). Так делать совершенно точно нельзя!Вот пример, насколько просто сбежать из такого контейнера (в самом простом случае):
# Запускаем контейнер
» docker run --name=first -v /var/run/docker.sock:/var/run/docker.sock -it docker:dind sh
# Внутри docker:
/ # ls -alh /var/run/docker.sock
srwxr-xr-x root /var/run/docker.sock
/ # hostname
700809c044d6 # <- наш текущий хост, контейнер `first`
/ # docker container ls
CONTAINER ID NAMES
e7d7857b965a other
700809c044d6 first
/ # docker exec -it other sh
/ # hostname
e7d7857b965a # <- мы получили доступ к соседнему контейнеру на хосте :(
Тут – просто вопиющий случай, который делает неправильно буквально все: выставляет
docker.sock и использует root внутри контейнера. Даже если вам нужно выставить docker.sock, то есть варианты лучше 2. Можно взять
docker:dind и запустить его с --privileged, прокинуть ему DOCKER_TLS_CERTDIR, запустить второй контейнер "клиент" без --privileged, но с нужными сертификатами, и выполнять все на нем. Такой способ уже безопаснее, но все равно есть много вариантов побега и privilege escalation Я подготовил пример такой сборки: https://gitverse.ru/sobolevn/dind-demo
3. Можно запускать контейнеры в изолированной виртуалке, которая будет быстро стартовать, работать и умирать. 0 рисков, никаких общих сокетов и возможности сбежать
GitHub и Packer
GitHub пошел по третьему пути. Когда мы указываем в actions:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: wemake-services/wemake-python-styleguide@1.1
То происходит следующее:
- GitHub берет образ виртуалки ubuntu-latest из заранее подготовленных
- Быстро разворачиваем готовый образ при помощи Instant Restore / InPlace Restore из Azure
- GitHub запускает контейнер с
wemake-services/wemake-python-styleguide и выполняет код action внутри dockerНо, внутри образов есть не только docker, там есть всё. Образ ubuntu весит 18GB 🫠
Но есть и минимальные виртуалки без всего. Собираются они при помощи packer.
Планы
GitVerse прямо сейчас разрабатывают что-то очень похожее. В планах:
- Разные ОС: разные linux, macos, windows
- Разные архитектуры: x86_64, arm
Кажется, что такой путь – очень удобный. Быстро, надежно, кастомизируемо.
Подпишись на их канал @gitversenews, чтобы быть в курсе всех новостей. Поддержка заинтересованных в развитии опенсорса продуктов и компаний, таких как GitVerse, помогает мне бесплатно делиться контентом с вами. Спасибо им большое за поддержку и помощь в подготовке поста.
Реклама. АО «СберТех»
ИНН:7736632467 Erid:2W5zFJeNAVn Сайт: https://gitverse.ru/home18+
👍59❤21🤮8🔥5🤡5👎3😁1🤔1
Perforator — система непрерывного профилирования для разных языков
https://github.com/yandex/perforator
Главные фичи:
> Efficient and high-quality collection of kernel + userspace stacks via eBPF
> Scalable storage for storing profiles and binaries
> Support of unwinding without frame pointers and debug symbols on host
> Convenient query language and UI to inspect CPU usage of applications via flamegraphs
> Support for C++, C, Go, and Rust, with experimental support for Java and Python
> Generation of sPGO profiles for building applications with Profile Guided Optimization (PGO) via AutoFDO
Но самое главное – у Perforator есть режим Continuous Profiling, где на сервак ставится агент, который передает информацию о производительности всех сервисов. На что тратит всего около 1% CPU.
Очень полезный и полный пост с анонсом на хабре.
Важное ограничение: пока работает только на x86_64 Linux, ARM поддержка планируется в ближайшем будущем.
Профилируем код на Python
Нас конечно же больше всего интересует, как данная штука умеет профилировать код на питоне.
Пока что работают только версии после 3.12, потому что нативная поддержка
Смотрим доку, как профилировать питон: https://perforator.tech/docs/en/tutorials/python-profiling
Сначала собираем при помощи
Прямо в примере в доке есть код, который будет работать неоптимально. Запустим его:
И запускаем профилировщик:
На
Перед тем, как его смотреть, нагрузим наш сервак простейшим скриптом:
Получится вот такой замечательный flamegraph.
Но! Пример из документации не заканчивается просто созданием графика, пример показывает, как его анализировать. Что очень важно. Далее нам предлагают найти узкое место в коде: https://perforator.tech/docs/en/tutorials/python-profiling#optimizing-the-bottleneck
После оптимизации получится так. Потребление CPU упадет с 96% до 26%
Чего хочется?
- Хочется поддержки macos для локального профилирования
- Хочется попробовать в реальном проде :)
- Хочется понять, насколько такие данные помогут средней компании писать более производительные сервисы
Обсуждение: как у вас в компаниях дела с Continuous Profiling?
Про Perforator я узнал благодаря своему старому и доброму товарищу – Евгению Антонову, он ведет канал про важные навыки для тимлидов и два подкаста: КодаКода – про менеджмент и харды, "Три тимлида заходят в бар" – про разные тимлидские штуки, которые будут безусловно полезны для тех, кто решил развиваться в данную ветку карьеры. Советую!
Хотите рассказать про свой опенсорс проект? Пишите в наш чат :)
| Поддержать | YouTube | GitHub | Чат |
https://github.com/yandex/perforator
Главные фичи:
> Efficient and high-quality collection of kernel + userspace stacks via eBPF
> Scalable storage for storing profiles and binaries
> Support of unwinding without frame pointers and debug symbols on host
> Convenient query language and UI to inspect CPU usage of applications via flamegraphs
> Support for C++, C, Go, and Rust, with experimental support for Java and Python
> Generation of sPGO profiles for building applications with Profile Guided Optimization (PGO) via AutoFDO
Но самое главное – у Perforator есть режим Continuous Profiling, где на сервак ставится агент, который передает информацию о производительности всех сервисов. На что тратит всего около 1% CPU.
Очень полезный и полный пост с анонсом на хабре.
Важное ограничение: пока работает только на x86_64 Linux, ARM поддержка планируется в ближайшем будущем.
Профилируем код на Python
Нас конечно же больше всего интересует, как данная штука умеет профилировать код на питоне.
Пока что работают только версии после 3.12, потому что нативная поддержка
perf появилась именно там: https://docs.python.org/3/howto/perf_profiling.html Смотрим доку, как профилировать питон: https://perforator.tech/docs/en/tutorials/python-profiling
Сначала собираем при помощи
docker в пару строк: https://perforator.tech/docs/en/guides/build#containerПрямо в примере в доке есть код, который будет работать неоптимально. Запустим его:
» python server.py
My pid is 53000
Serving on port 9007
И запускаем профилировщик:
sudo perforator record --pid $YOUR_PID --duration 1m --serve ":9006"На
http://localhost:9006 вас будет ждать flamegraph работы скрипта.Перед тем, как его смотреть, нагрузим наш сервак простейшим скриптом:
import requests
import random
while True:
user_id = random.randint(1, 1000000)
requests.get(f"http://localhost:9007/search_user?user_id={user_id}")
Получится вот такой замечательный flamegraph.
Но! Пример из документации не заканчивается просто созданием графика, пример показывает, как его анализировать. Что очень важно. Далее нам предлагают найти узкое место в коде: https://perforator.tech/docs/en/tutorials/python-profiling#optimizing-the-bottleneck
После оптимизации получится так. Потребление CPU упадет с 96% до 26%
Чего хочется?
- Хочется поддержки macos для локального профилирования
- Хочется попробовать в реальном проде :)
- Хочется понять, насколько такие данные помогут средней компании писать более производительные сервисы
Обсуждение: как у вас в компаниях дела с Continuous Profiling?
Про Perforator я узнал благодаря своему старому и доброму товарищу – Евгению Антонову, он ведет канал про важные навыки для тимлидов и два подкаста: КодаКода – про менеджмент и харды, "Три тимлида заходят в бар" – про разные тимлидские штуки, которые будут безусловно полезны для тех, кто решил развиваться в данную ветку карьеры. Советую!
Хотите рассказать про свой опенсорс проект? Пишите в наш чат :)
| Поддержать | YouTube | GitHub | Чат |
GitHub
GitHub - yandex/perforator: Perforator is a cluster-wide continuous profiling tool designed for large data centers
Perforator is a cluster-wide continuous profiling tool designed for large data centers - yandex/perforator
👍59🔥28❤9🤯4🤡2
PEP 750: t-строки в 3.14
В питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций.
- PEP: https://peps.python.org/pep-0750
- Реализация: https://github.com/python/cpython/pull/132662
Основная причина: использовать
string.templatelib.Template
Новый префикс
Обратите внимание, что при создании
Давайте посмотрим на примере. Допустим, мы хотим формировать URL из наших данных:
И сам код логики форматирования, где мы будем вставлять значения разным способом. Если у нас шаблон
И вот результат:
Только теперь наш
У нас есть полный контроль за процессом форматирования. Вот в чем суть данного ПЕПа.
Фичи одной строкой
- Работает
- Есть привычные определители формата:
-
- Поддерживается режим raw строк:
Как устроено внутри?
Интересные места имплементации:
- Изменения лексера
- Изменения грамматики языка
- Новое CAPI
- Новые классы
- Новый байткод
Обсуждение: как вам еще один способ форматирования строк?
| Поддержать | YouTube | GitHub | Чат |
В питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций.
- PEP: https://peps.python.org/pep-0750
- Реализация: https://github.com/python/cpython/pull/132662
Основная причина: использовать
f строки удобно, но нет никакого АПИ для перехвата момента "вставки" или интерполяции значений. Например, при форматировании html или sql – требуется специальным образом делать escape для значений. И раньше код вида f"<div>{template}</div>" представлял собой дыру в безопасности и потенциальное место для XSS.string.templatelib.Template
Новый префикс
t не будет создавать объект str, он будет создавать объект класса string.templatelib.Template:
>>> user = 'sobolevn'
>>> template = t"Hi, {user}"
>>> template
Template(strings=('Hi, ', ''), interpolations=(Interpolation('sobolevn', 'user', None, ''),))
>>> from string.templatelib import Template
>>> isinstance(template, Template)
True
Обратите внимание, что при создании
template – у нас не произошло форматирование сразу. Мы создали объект, у которого есть свойства strings и interpolations, из которых можно собрать финальную отформатированную строку.Давайте посмотрим на примере. Допустим, мы хотим формировать URL из наших данных:
>>> domain = 'example.com'
>>> query = 'python string formatting is too complex'
>>> template = t'https://{domain}?q={query}'
И сам код логики форматирования, где мы будем вставлять значения разным способом. Если у нас шаблон
query, то мы будем использовать quote_plus для его форматирования. Остальные значения – будем вставлять как есть:
>>> from string.templatelib import Template, Interpolation
>>> from urllib.parse import quote_plus
>>> def format_url(template: Template) -> str:
... parts = []
... for part in template:
... match part:
... case str() as s: # regular string
... parts.append(s)
... case Interpolation(value, expression='query'):
... parts.append(quote_plus(value))
... case Interpolation(value):
... parts.append(value)
... return ''.join(parts)
И вот результат:
>>> format_url(template)
'https://example.com?q=python+string+formatting+is+too+complex'
Только теперь наш
Template был отформатирован. Нами. Ручками.У нас есть полный контроль за процессом форматирования. Вот в чем суть данного ПЕПа.
Фичи одной строкой
- Работает
= как обычно в f строках: t'{user=}'- Есть привычные определители формата:
!r, !s, .2f, тд-
t строки можно конкатенировать: t'Hello' + t' , world!' и t'Hello, ' + 'world'- Поддерживается режим raw строк:
rt"Hi \n!"Как устроено внутри?
Интересные места имплементации:
- Изменения лексера
- Изменения грамматики языка
- Новое CAPI
_PyTemplate- Новые классы
Template и Interpolation написанные на C- Новый байткод
BUILD_INTERPOLATION и BUILD_TEMPLATE
>>> import dis
>>> user = 'sobolevn'
>>> dis.dis('t"Hi, {user}"')
0 RESUME 0
1 LOAD_CONST 2 (('Hi, ', ''))
LOAD_NAME 0 (user)
LOAD_CONST 1 ('user')
BUILD_INTERPOLATION 2
BUILD_TUPLE 1
BUILD_TEMPLATE
RETURN_VALUE
Обсуждение: как вам еще один способ форматирования строк?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 750 – Template Strings | peps.python.org
This PEP introduces template strings for custom string processing.
11👍120🔥48🤔14❤11👎4🎉3😱1🤮1🤡1
Первый чемпионат по опенсорсной настолке про IT: Ship IT!
Как вы можете знать, я сделал опенсорсую настолку про IT: github.com/sobolevn/ship-it-boardgame
Её можно бесплатно распечатать и поиграть. Она так же есть бесплатно в стиме для Table Top Simulator.
Игра от 2 до 5 игроков, от 30 до 45 минут, для игроков 16+
Шуточная игра для тех, кто любит IT. Первыми задеплойте все компоненты вашей архитектуры в прод и победите конкурентов! И прямо как в настоящей жизни нужно: душить и отменять своих коллег, следить за своей инфраструктурой и не деплоить в пятницу, применять
PiterPy
Но, у меня есть новости куда круче. На ближайшем PiterPy – мы устроим первый официальный чемпионат по Ship IT!
Формат: 10 минут на разминочную игру. Далее 3 полных круга, победители проходят дальше.
Ведущий: я!
Призы: за выход в финал – настольная игра. За победу – бесплатный билет на любую конференцию jug.ru по вашему выбору. 🏆
Правила: https://github.com/sobolevn/ship-it-boardgame/blob/master/ru/rules.md
Играем в душный режим с фрилансом!
Версия игры: 0.0.23
Обязательно перед игрой прочитайте правила игры, если еще не играли :) Можно предварительно потренироваться в Steam'е с друзьями или нашей группе.
Дата и время: 16 мая, на вечеринке PiterPy + IML. Начало в 19:30.
Место: Зал 4.
✅ Регистрация на игру обязательна: https://docs.google.com/forms/d/e/1FAIpQLSctYdyrcSPKFY79o4A5-1-FZxIUnoIcjHuELFTDlkoRMA4Q_w/viewform
Жду всех настольщиков на настоящую зарубу!
Как вы можете знать, я сделал опенсорсую настолку про IT: github.com/sobolevn/ship-it-boardgame
Её можно бесплатно распечатать и поиграть. Она так же есть бесплатно в стиме для Table Top Simulator.
Игра от 2 до 5 игроков, от 30 до 45 минут, для игроков 16+
Шуточная игра для тех, кто любит IT. Первыми задеплойте все компоненты вашей архитектуры в прод и победите конкурентов! И прямо как в настоящей жизни нужно: душить и отменять своих коллег, следить за своей инфраструктурой и не деплоить в пятницу, применять
sudo, выгорать и воровать, находить ошибки и уязвимости в чужих приложения. Игра с нешуточными последствиями!PiterPy
Но, у меня есть новости куда круче. На ближайшем PiterPy – мы устроим первый официальный чемпионат по Ship IT!
Формат: 10 минут на разминочную игру. Далее 3 полных круга, победители проходят дальше.
Ведущий: я!
Призы: за выход в финал – настольная игра. За победу – бесплатный билет на любую конференцию jug.ru по вашему выбору. 🏆
Правила: https://github.com/sobolevn/ship-it-boardgame/blob/master/ru/rules.md
Играем в душный режим с фрилансом!
Версия игры: 0.0.23
Обязательно перед игрой прочитайте правила игры, если еще не играли :) Можно предварительно потренироваться в Steam'е с друзьями или нашей группе.
Дата и время: 16 мая, на вечеринке PiterPy + IML. Начало в 19:30.
Место: Зал 4.
✅ Регистрация на игру обязательна: https://docs.google.com/forms/d/e/1FAIpQLSctYdyrcSPKFY79o4A5-1-FZxIUnoIcjHuELFTDlkoRMA4Q_w/viewform
Жду всех настольщиков на настоящую зарубу!
❤37🔥29🤔8👍6🤡2
PEP 758: except и except* без ()
- PEP: https://peps.python.org/pep-0758
- PR: https://github.com/python/cpython/pull/131833
В 3.14 мы теперь можем не указывать скобки в
Раньше нам необходимо было писать так:
Удобно? Удобно. Однако, когда есть
Правильно будет так:
Как работает?
На самом деле – изменение очень маленькое, что позволит нам сфокусироваться на работе парсера. Смотрите, было:
Стало:
Что тут есть что?
1.
2. через
3. первое правило – особенное, все правила с префиксом
4. второе правило – ключевое слово
5. третье правило – ключевое слово
Разница, что раньше не было пункта
Вот такое простое, но довольно удобное изменение.
Обсуждение: какой стиль вы выберете у себя в команде?
Extra: кстати, в коде новой грамматики из PR (который я привел выше) была ошибка, которую я уже исправил. Нашли?
| Поддержать | YouTube | GitHub | Чат |
- PEP: https://peps.python.org/pep-0758
- PR: https://github.com/python/cpython/pull/131833
В 3.14 мы теперь можем не указывать скобки в
except и except*, когда мы ловим несколько типов исключений и не используем as, пример:
>>> try:
... res = int(data['value'])
... except ValueError, KeyError:
... res = 0
Раньше нам необходимо было писать так:
>>> try:
... res = int(data['value'])
... except (ValueError, KeyError):
... res = 0
Удобно? Удобно. Однако, когда есть
as мы все еще должны использовать скобки:
>>> try:
... res = int(data['value'])
... except ValueError, KeyError as exc:
... res = 0
...
File "<python-input-3>", line 3
except ValueError, KeyError as exc:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: multiple exception types must be parenthesized when using 'as'
Правильно будет так:
>>> try:
... res = int(data['value'])
... except (ValueError, KeyError) as exc:
... res = 0
Как работает?
На самом деле – изменение очень маленькое, что позволит нам сфокусироваться на работе парсера. Смотрите, было:
except_block[excepthandler_ty]:
| invalid_except_stmt_indent
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
Стало:
except_block[excepthandler_ty]:
| invalid_except_stmt_indent
| 'except' e=expressions ':' b=block {
_PyAST_ExceptHandler(e, NULL, b, EXTRA) }
| 'except' e=expression 'as' t=NAME ':' b=block {
_PyAST_ExceptHandler(e, ((expr_ty) t)->v.Name.id, b, EXTRA) }
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
Что тут есть что?
1.
except_block большое правило, которое умеет парсить except в его разных видах. excepthandler_ty – его Cшный тип, такое упрощение для кодогенерации конечного parser.c2. через
| указаны варианты, какие могут быть грамматически корректные except в Python3. первое правило – особенное, все правила с префиксом
invalid_ – работают только на второй прогон парсера, чтобы показывать более качественные ошибки пользователям4. второе правило – ключевое слово
except, потом любые выражения, но без as5. третье правило – ключевое слово
except, потом любое одно выражение, далее asРазница, что раньше не было пункта
4., а as был опциональный (внутри [] скобок в описании грамматики)Вот такое простое, но довольно удобное изменение.
Обсуждение: какой стиль вы выберете у себя в команде?
Extra: кстати, в коде новой грамматики из PR (который я привел выше) была ошибка, которую я уже исправил. Нашли?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 758 – Allow except and except* expressions without parentheses | peps.python.org
This PEP 1 proposes to allow unparenthesized except and except* blocks in Python’s exception handling syntax only when not using the as clause. Currently, when catching multiple exceptions, parentheses are required around the exception types. This was a...
4❤33👍23🔥16👎5🤔5🤡1
В Python3.14 добавили подсветку синтаксиса в новом PyREPL
- PR: https://github.com/python/cpython/pull/133247
Выглядит прикольно. А еще можно делать свои темы, вот пример дефолтной:
Свою можно поставить так:
1. Меняем цвета для тех токенов, которые хотим подсветить. Складываем в импортируемый модуль. Например:
2. При старте – устанавливаем свою тему
Доки про
Вот тут реализация подсветки, она довольно простая.
Ждем реализацию pustota для PyREPL?
| Поддержать | YouTube | GitHub | Чат |
- PR: https://github.com/python/cpython/pull/133247
Выглядит прикольно. А еще можно делать свои темы, вот пример дефолтной:
theme = {
"PROMPT": colors.BOLD_MAGENTA,
"KEYWORD": colors.BOLD_BLUE,
"BUILTIN": colors.CYAN,
"COMMENT": colors.RED,
"STRING": colors.GREEN,
"NUMBER": colors.YELLOW,
"OP": colors.RESET,
"DEFINITION": colors.BOLD,
"SOFT_KEYWORD": colors.BOLD_BLUE,
"RESET": colors.RESET,
}
Свою можно поставить так:
1. Меняем цвета для тех токенов, которые хотим подсветить. Складываем в импортируемый модуль. Например:
your_theme2. При старте – устанавливаем свою тему
export PYTHONSTARTUP='import _colorize; from your_theme import theme; _colorize.set_theme(theme)'
Доки про
PYTHONSTARTUP: https://docs.python.org/3/using/cmdline.html#envvar-PYTHONSTARTUPВот тут реализация подсветки, она довольно простая.
Ждем реализацию pustota для PyREPL?
| Поддержать | YouTube | GitHub | Чат |
👍84🔥36🤡8❤7🤩2
Находки в опенсорсе: ty (red-knot)
https://www.youtube.com/watch?v=5PCP4ICoirg
Вышло видео про новый тайпчекер и lsp: ty (старое название
Пока по первым впечатлениям – бомба! Не смотря на версию
Из плюсов:
- Быстрый
- На расте
- Куча новых фичей для типов
- Полная спецификация
- Интеграция с
Из минусов:
- Пока есть баги (но их поправят, конечно же)
- Нет плагинов (и скорее всего никогда не будет)
- Софт от молодой и маленькой компании
- Как сделать поддержку
Обсуждение: а как вам проект? Успели попробовать?
| Поддержать | YouTube | GitHub | Чат |
https://www.youtube.com/watch?v=5PCP4ICoirg
Вышло видео про новый тайпчекер и lsp: ty (старое название
red-knot) от авторов ruff и uv.Пока по первым впечатлениям – бомба! Не смотря на версию
0.0.0a8 🌚Из плюсов:
- Быстрый
- На расте
- Куча новых фичей для типов
- Полная спецификация
- Интеграция с
ruff и IDEшкамиИз минусов:
- Пока есть баги (но их поправят, конечно же)
- Нет плагинов (и скорее всего никогда не будет)
- Софт от молодой и маленькой компании
- Как сделать поддержку
ty и mypy вместе? Если использовались ty_extensions 🤷♂️Обсуждение: а как вам проект? Успели попробовать?
| Поддержать | YouTube | GitHub | Чат |
YouTube
Находки в опенсорсе: ty (red-knot)
ty – новый тайпчекер для Python (ранее известный как red-knot) от авторов ruff, компании Astral, написанный на Rust.
Ссылки из выпуска:
- Попробовать: https://play.ty.dev
- Проект: https://github.com/astral-sh/ty
- Подкаст с авторами: https://www.youtub…
Ссылки из выпуска:
- Попробовать: https://play.ty.dev
- Проект: https://github.com/astral-sh/ty
- Подкаст с авторами: https://www.youtub…
5❤63🔥24🤔8👍7🕊2🤡2💩1
unraisable exceptions в питоне
Мы все с вами привыкли, что в питоне можно "зарайзить" исключение в любой момент:
Но, что если в какой-то момент времени мы не можем вызывать исключение?
Простейший пример: что произойдет при запуске такого скрипта?
Тут может быть два варианта:
1. Или
2. Или случится какая-то магия, ошибка будет вызвана, напечатается, но программа продолжится
Ну и так как мы с вами на том канале, где мы с вами, то конечно же будет второй вариант.
Знакомьтесь – unraisable exceptions 🤝
Как оно работает?
В некоторых местах C кода у нас есть необходимость вызывать исключения, но нет технической возможности. Пример, как выглядит упрощенный
А, как вы можете знать, чтобы в C коде вызвать ошибку, нужно сделать две вещи:
- Взывать специальное АПИ вроде
- И вернуть
Ошибку мы "вызываем" через специальные АПИ:
- PyErr_WriteUnraisable
- PyErr_FormatUnraisable
Они создают ошибку, но не выкидывают её обычным способом, а сразу отправляют в специальный хук-обработчик.
В питоне оно используется где-то 150 раз. То есть – прям часто. Примеры:
- Ошибки при завершении интерпретатора, попробуйте сами:
- Ошибки внутри sys.excepthook
- Ошибки внутри
- Ошибки внутри логики установки ошибок (вдруг память кончилась, например) 🌚️️️️
- И многое другое
Пользовательское АПИ
Ну и конечно же, есть специальный хук для обработки таких ошибок: sys.unraisablehook
Например, pytest использует кастомный хук, чтобы валить тесты при возникновении такой ситуации. Что логично.
Обсуждение: знали ли вы про такую особенность? Приходилось ли где-то в мониторинге особо настраивать?
| Поддержать | YouTube | GitHub | Чат |
Мы все с вами привыкли, что в питоне можно "зарайзить" исключение в любой момент:
raise ExceptionНо, что если в какой-то момент времени мы не можем вызывать исключение?
Простейший пример: что произойдет при запуске такого скрипта?
# ex.py
class BrokenDel:
def __del__(self):
raise ValueError('del is broken')
obj = BrokenDel()
del obj
print('done!') # будет ли выведено?
Тут может быть два варианта:
1. Или
del вызовет ValueError и программа завершится2. Или случится какая-то магия, ошибка будет вызвана, напечатается, но программа продолжится
Ну и так как мы с вами на том канале, где мы с вами, то конечно же будет второй вариант.
» ./python.exe ex.py
Exception ignored while calling deallocator <function BrokenDel.__del__ at 0x10303c1d0>:
Traceback (most recent call last):
File "/Users/sobolev/Desktop/cpython/ex.py", line 3, in __del__
raise ValueError('del is broken')
ValueError: del is broken
done!
Знакомьтесь – unraisable exceptions 🤝
Как оно работает?
В некоторых местах C кода у нас есть необходимость вызывать исключения, но нет технической возможности. Пример, как выглядит упрощенный
dealloc для list?
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op); // убираем объект из отслеживания gc
if (op->ob_item != NULL) {
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]); // уменьшаем счетчик ссылок каждого объекта в списке
}
op->ob_item = NULL;
}
PyObject_GC_Del(op);
}
А, как вы можете знать, чтобы в C коде вызвать ошибку, нужно сделать две вещи:
- Взывать специальное АПИ вроде
PyErr_SetString(PyExc_ValueError, "some text")- И вернуть
NULL как PyObject * из соответствующих АПИ, показывая, что у нас ошибка. Если вернуть NULL нельзя, то мы не можем поставить ошибку. А тут у нас void и вернуть вообще ничего нельзя. Потому приходится использовать вот такой подход с unraisable exceptionОшибку мы "вызываем" через специальные АПИ:
- PyErr_WriteUnraisable
- PyErr_FormatUnraisable
Они создают ошибку, но не выкидывают её обычным способом, а сразу отправляют в специальный хук-обработчик.
В питоне оно используется где-то 150 раз. То есть – прям часто. Примеры:
- Ошибки при завершении интерпретатора, попробуйте сами:
import atexit
def foo():
raise Exception('foo')
atexit.register(foo)
- Ошибки внутри sys.excepthook
- Ошибки внутри
gc- Ошибки внутри логики установки ошибок (вдруг память кончилась, например) 🌚️️️️
- И многое другое
Пользовательское АПИ
Ну и конечно же, есть специальный хук для обработки таких ошибок: sys.unraisablehook
Например, pytest использует кастомный хук, чтобы валить тесты при возникновении такой ситуации. Что логично.
Обсуждение: знали ли вы про такую особенность? Приходилось ли где-то в мониторинге особо настраивать?
| Поддержать | YouTube | GitHub | Чат |
Python documentation
Exception Handling
The functions described in this chapter will let you handle and raise Python exceptions. It is important to understand some of the basics of Python exception handling. It works somewhat like the PO...
7🤯111🔥36👍28❤4👎1🤡1
В Python3.14 добавили новую библиотеку для сжатия: Zstandard
- PEP: https://peps.python.org/pep-0784
- Документация: https://docs.python.org/3.14/library/compression.zstd.html
- Реализация: https://github.com/python/cpython/pull/133027
Существует такой новый алгоритм для сжатия: Zstandard c хорошим процентом сжатия и быстрым алгоритмом сжатия / разжатия. Его добавили в 3.14 как нативный модуль. И как раз заодно решили прибрать все другие алгоритмы в общий модуль
Теперь:
-
-
-
Пока данные новые модули просто делают re-export всех объектов из оригинальных модулей. Однако, в какой-то момент старые имена могут быть задеприкейчены.
> Any deprecation or removal of the existing modules is left to a future decision but will occur no sooner than 5 years from the acceptance of this PEP.
Как работает?
Сам алгоритм сжатия хорошо описан в соответствующем RFC. Его лучше почитать отдельно. Тем, кому такое интересно.
А мы поговорим про питоновскую часть.
Теперь питон зависит от новой опциональной библиотеки
Мы используем AutoConf или
Самая важная часть:
Генерируется в результате вот такой трешняк: https://github.com/python/cpython/blob/30dde1eeb3fa1e0e7417f9cdded8fd90766f2559/configure#L22587-L22946
Данная мешанина из shell, C кода в строках и безумной обработки ошибок делает следующее:
- записывает файл с Сишным кодом
- вставляет туда нужные хедеры
- пытается скомпилировать
- если получилось, то пишет один конфиг
- если нет, то сборка понимает, что библиотеки нет, пишется другой конфиг
- на основе
Вот тут мы указываем, какие части компилировать, если такая библиотека есть:
Посмотрим, как выглядит
А если такой библиотеки нет – то в итоговом
Обсуждение: как вам данный алгоритм сжатия? Как вам система сборки питона?
- PEP: https://peps.python.org/pep-0784
- Документация: https://docs.python.org/3.14/library/compression.zstd.html
- Реализация: https://github.com/python/cpython/pull/133027
Существует такой новый алгоритм для сжатия: Zstandard c хорошим процентом сжатия и быстрым алгоритмом сжатия / разжатия. Его добавили в 3.14 как нативный модуль. И как раз заодно решили прибрать все другие алгоритмы в общий модуль
compression.*Теперь:
-
compression.lzma отвечает за lzma-
compression.zstd за Zstandard-
compression.gzip за gzip и так далееПока данные новые модули просто делают re-export всех объектов из оригинальных модулей. Однако, в какой-то момент старые имена могут быть задеприкейчены.
> Any deprecation or removal of the existing modules is left to a future decision but will occur no sooner than 5 years from the acceptance of this PEP.
Как работает?
Сам алгоритм сжатия хорошо описан в соответствующем RFC. Его лучше почитать отдельно. Тем, кому такое интересно.
А мы поговорим про питоновскую часть.
Теперь питон зависит от новой опциональной библиотеки
zstd.h, что будет, если ее нет? И тут мы должны познакомиться с системой конфигурации и сборки питона.Мы используем AutoConf или
.ac. Данный зверь – свой большой мир, который хочется как раз показать на примере. Спорим, вы не сможете с первого раза прочитать данную конструкцию?
dnl zstd 1.4.5 stabilised ZDICT_finalizeDictionary
PKG_CHECK_MODULES([LIBZSTD], [libzstd >= 1.4.5], [have_libzstd=yes], [
WITH_SAVE_ENV([
CPPFLAGS="$CPPFLAGS $LIBZSTD_CFLAGS"
CFLAGS="$CFLAGS $LIBZSTD_CFLAGS"
LIBS="$LIBS $LIBZSTD_LIBS"
AC_SEARCH_LIBS([ZDICT_finalizeDictionary], [zstd], [
AC_MSG_CHECKING([ZSTD_VERSION_NUMBER >= 1.4.5])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([@%:@include "zstd.h"], [
#if ZSTD_VERSION_NUMBER < 10405
# error "zstd version is too old"
#endif
])
], [
AC_MSG_RESULT([yes])
AC_CHECK_HEADERS([zstd.h zdict.h], [have_libzstd=yes], [have_libzstd=no])
], [
AC_MSG_RESULT([no])
have_libzstd=no
])
], [have_libzstd=no])
AS_VAR_IF([have_libzstd], [yes], [
LIBZSTD_CFLAGS=${LIBZSTD_CFLAGS-""}
LIBZSTD_LIBS=${LIBZSTD_LIBS-"-lzstd"}
])
])
])
Самая важная часть:
AC_CHECK_HEADERS([zstd.h zdict.h], [have_libzstd=yes], [have_libzstd=no]), она проверяет наличие нужных хедеров / зависимостей для компиляции. Данный код создает несколько проверок при генерации файла ./configure, которые позволяют проверить, есть ли такая библиотека на машине сборки.Генерируется в результате вот такой трешняк: https://github.com/python/cpython/blob/30dde1eeb3fa1e0e7417f9cdded8fd90766f2559/configure#L22587-L22946
Данная мешанина из shell, C кода в строках и безумной обработки ошибок делает следующее:
- записывает файл с Сишным кодом
- вставляет туда нужные хедеры
- пытается скомпилировать
- если получилось, то пишет один конфиг
- если нет, то сборка понимает, что библиотеки нет, пишется другой конфиг
- на основе
./configure потом собирается правильный Makefile для компиляции самого питонаВот тут мы указываем, какие части компилировать, если такая библиотека есть:
@MODULE__ZSTD_TRUE@_zstd _zstd/_zstdmodule.c _zstd/zstddict.c _zstd/compressor.c _zstd/decompressor.c
Посмотрим, как выглядит
Makefile, если библиотека есть:
MODULE__ZSTD_STATE=yes
MODULE__ZSTD_CFLAGS=-I/opt/homebrew/opt/zstd/include
MODULE__ZSTD_LDFLAGS=-L/opt/homebrew/opt/zstd/lib -lzstd
Modules/_zstd/_zstdmodule.o: $(srcdir)/Modules/_zstd/_zstdmodule.c $(MODULE__ZSTD_DEPS) $(MODULE_DEPS_SHARED) $(PYTHON_HEADERS); $(CC) $(MODULE__ZSTD_CFLAGS) $(PY_STDMODULE_CFLAGS) $(CCSHARED) -c $(srcdir)/Modules/_zstd/_zstdmodule.c -o Modules/_zstd/_zstdmodule.o
# ...
А если такой библиотеки нет – то в итоговом
Makefile просто не будет данной цели для сборки.Обсуждение: как вам данный алгоритм сжатия? Как вам система сборки питона?
Python Enhancement Proposals (PEPs)
PEP 784 – Adding Zstandard to the standard library | peps.python.org
Zstandard is a widely adopted, mature, and highly efficient compression standard. This PEP proposes adding a new module to the Python standard library containing a Python wrapper around Meta’s zstd library, the default implementation. Additionally, to a...
1👍79🔥22❤19🤯9😁4🤡2👌1🕊1
__code__.co_exceptiontable: начало
Чтобы познакомиться с таблицами обработки исключений, нам потребуется нырнуть глубоко.
Базовая идея: таблица исключений показывает, какие строки байткода покрыты обработчиками ошибок, а какие – нет. По сути – таблица неявных переходов между логическими лейблами. За счет данной технологии реализованы питоновские "zero-cost exceptions".
Возьмем для примера вот такую простую функцию:
Получим вот такие: байткод (полная версия по ссылке) и таблицу исключений:
Что она делает?
Если на каком-то участке байткода возникает исключение, то мы прыгаем на нужную логическую метку из таблицы. Пример: в
У данной функции будет 3 интересных для нас куска байткода.
Первый – про обработку
Тут мы просто делим два объекта и печатаем. Из интересного тут то, что
Второй – про вызов
Тут мы сравниваем тип ошибки, если она
И третий после необработанного исключения:
Здесь происходит самое интересное. Нам необходимо правильно обработать ошибки, которые могут случиться в
-
-
Пример, как будут выполняться разные кейсы:
-
-
-
Ссылки на исходники:
- RERAISE
- exception_unwind для поиска обработчика текущей ошибки
- get_exception_handler для разворачивания таблицы
Обсуждение: как часто вы пользуетесь
| Поддержать | YouTube | GitHub | Чат |
Чтобы познакомиться с таблицами обработки исключений, нам потребуется нырнуть глубоко.
Базовая идея: таблица исключений показывает, какие строки байткода покрыты обработчиками ошибок, а какие – нет. По сути – таблица неявных переходов между логическими лейблами. За счет данной технологии реализованы питоновские "zero-cost exceptions".
Возьмем для примера вот такую простую функцию:
def other(x, y):
res = None
try:
res = x / y
except ZeroDivisionError:
res = 0
finally:
print(res)
Получим вот такие: байткод (полная версия по ссылке) и таблицу исключений:
ExceptionTable:
L1 to L2 -> L3 [0]
L3 to L4 -> L6 [1] lasti
L4 to L5 -> L7 [0]
L5 to L6 -> L6 [1] lasti
L6 to L7 -> L7 [0]
L7 to L8 -> L8 [1] lasti
Что она делает?
Если на каком-то участке байткода возникает исключение, то мы прыгаем на нужную логическую метку из таблицы. Пример: в
try (метки c L1 по L2 невключительно) прыгаем на L3.У данной функции будет 3 интересных для нас куска байткода.
Первый – про обработку
finally после успешного случая:
3 L1: LOAD_FAST_BORROW_LOAD_FAST_BORROW 1 (x, y)
BINARY_OP 11 (/)
STORE_FAST 2 (res)
7 L2: LOAD_GLOBAL 3 (print + NULL)
LOAD_FAST_BORROW 2 (res)
CALL 1
POP_TOP
LOAD_CONST 1 (None)
RETURN_VALUE
Тут мы просто делим два объекта и печатаем. Из интересного тут то, что
finally разложился в набор байткода прямо после тела try. Нам не нужно никаких дополнительных манипуляций, чтобы управлять указателем на следующую инструкцию. Так происходит благодаря псевдо-инструкции SETUP_FINALLY. Так было не всегда, раньше тут был JUMP_FORWARD, а finally был общий для всех.Второй – про вызов
finally после обработанного ZeroDivisionError исключения:
-- L3: PUSH_EXC_INFO
4 LOAD_GLOBAL 0 (ZeroDivisionError)
CHECK_EXC_MATCH
POP_JUMP_IF_FALSE 6 (to L5)
NOT_TAKEN
POP_TOP
5 LOAD_SMALL_INT 0
STORE_FAST 2 (res)
L4: POP_EXCEPT
JUMP_BACKWARD_NO_INTERRUPT 28 (to L2)
Тут мы сравниваем тип ошибки, если она
ZeroDivisionError, то обрабатываем, в конце обработки ошибки прыгаем к L2. Если ошибка другая, то прыгаем в L5 (будет ниже). Из интересного, POP_EXCEPT убирает текущее исключение из tstate->exc_info, так исключение считается обработанным. И третий после необработанного исключения:
4 L5: RERAISE 0
-- L6: COPY 3
POP_EXCEPT
RERAISE 1
L7: PUSH_EXC_INFO
7 LOAD_GLOBAL 3 (print + NULL)
LOAD_FAST_CHECK 2 (res)
CALL 1
POP_TOP
RERAISE 0
-- L8: COPY 3
POP_EXCEPT
RERAISE 1
Здесь происходит самое интересное. Нам необходимо правильно обработать ошибки, которые могут случиться в
except и finally блоках. Для такого у нас есть:-
L3 to L4 -> L6 [1] lasti для обработки ошибок в except-
L7 to L8 -> L8 [1] lasti для обработки ошибок в finallyПример, как будут выполняться разные кейсы:
-
other(1, 2): L1 -> L2 (finally)-
other(1, 0): L1 -> L3 -> L4 -> L2 (finally)-
other(1, 'a'): L1 -> L3 (TypeError) -> L5 -> L7 (finally) -> L8Ссылки на исходники:
- RERAISE
- exception_unwind для поиска обработчика текущей ошибки
- get_exception_handler для разворачивания таблицы
Обсуждение: как часто вы пользуетесь
finally в обработке сложных ошибок?| Поддержать | YouTube | GitHub | Чат |
Gist
finally_bytecode.py
GitHub Gist: instantly share code, notes, and snippets.
1🔥51🤯13❤12👍3🤔3🤡1
Находки в опенсорсе
Находки в опенсорсе: ty (red-knot) https://www.youtube.com/watch?v=5PCP4ICoirg Вышло видео про новый тайпчекер и lsp: ty (старое название red-knot) от авторов ruff и uv. Пока по первым впечатлениям – бомба! Не смотря на версию 0.0.0a8 🌚 Из плюсов: - Быстрый…
Находки в опенсорсе: pyrefly
https://youtube.com/watch?v=7TdxFGB6LKY
Еще одно видео про еще один новый тайпчекер для питона на расте!
Много их нынче стало.
В видео:
- Обсуждаем первую версию:
- Сравниваем
- Смотрим на внутреннее устройство
- Применяем на реальном проекте
Ключевые ссылки из выпуска:
– Доклад о pyrefly на PyCon: https://youtu.be/ZTSZ1OCUaeQ?si=s_DPOOzsdeTk5Uqo
– pyrefly vs ty: https://blog.edward-li.com/tech/comparing-pyrefly-vs-ty (сильно советую!)
Вывод: пока очень сырой, много багов, но быстрый. Ключевой вывод: отлично, что есть конкуренция
https://youtube.com/watch?v=7TdxFGB6LKY
Еще одно видео про еще один новый тайпчекер для питона на расте!
Много их нынче стало.
В видео:
- Обсуждаем первую версию:
pyre-check, обсудили taint analysis- Сравниваем
pyrefly с ty и mypy- Смотрим на внутреннее устройство
- Применяем на реальном проекте
Ключевые ссылки из выпуска:
– Доклад о pyrefly на PyCon: https://youtu.be/ZTSZ1OCUaeQ?si=s_DPOOzsdeTk5Uqo
– pyrefly vs ty: https://blog.edward-li.com/tech/comparing-pyrefly-vs-ty (сильно советую!)
Вывод: пока очень сырой, много багов, но быстрый. Ключевой вывод: отлично, что есть конкуренция
YouTube
Находки в опенсорсе: pyrefly
pyrefly – новый тайпчекер для Python написанный на Rust. Вторая версия тайпчерека pyre-check.
Ссылки из выпуска:
– Попробовать: https://pyrefly.org/sandbox
– Проект: https://github.com/facebook/pyrefly
– Доклад о pyrefly на PyCon: https://www.youtube.co…
Ссылки из выпуска:
– Попробовать: https://pyrefly.org/sandbox
– Проект: https://github.com/facebook/pyrefly
– Доклад о pyrefly на PyCon: https://www.youtube.co…
26🔥43❤9🤡5👍4
PEP-734: Subinterpreters in stdlib
- PEP: https://peps.python.org/pep-0734
- Обсуждение: https://discuss.python.org/t/pep-734-multiple-interpreters-in-the-stdlib/41147
- Документация: https://docs.python.org/3.14/library/concurrent.interpreters.html
Что оно такое?
Несколько полноценных интерпретаторов работающих рядом. Какие плюсы?
- Один процесс
- Один тред, но руками можно создавать еще
- Простые данные можно шарить без необходимости pickle, сложные нужно пиклить
- По GILу на интерпретатор, все еще можно получить плюшки настоящей многозадачности по сети
- Работает с asyncio
Минусы:
-
Получается хорошая универсальность для разных задач.
Немного истории
Есть несколько важных нетехнических аспектов про процесс создания данной фичи:
- PEP-734 и Free-Threading делают очень похожие вещи – позволяют реализовывать настоящую многозадачность, но разными способами
- Изначально субинтерпретаторы появились в 3.10 в виде только C-шного АПИ
- Есть отдельный PyPI пакет с данным кодом
- Пайтон часть в виде PEP-734 был добавлена в 3.14 уже после feature freeze
- Изначально планировалось добавить его как модуль interpreters, однако в последний момент он стал concurrent.interpreters, вот тут доступно большое обсуждение
Как работает?
Внутри довольно много разных C-шных модулей:
- Основа: https://github.com/python/cpython/blob/main/Python/crossinterp.c
- Дефиниция модуля: https://github.com/python/cpython/blob/main/Modules/_interpretersmodule.c
- Очередь для обмена сообщениями между интерпретаторами: https://github.com/python/cpython/blob/main/Modules/_interpqueuesmodule.c
- Набор примитивов: https://github.com/python/cpython/blob/main/Modules/_interpchannelsmodule.c
Но, для пользователей - важен только питоновский АПИ, что прекрасно. Он получился простым и понятным:
Давайте посмотрим на пример и замерим!
Тестирую на M2Pro 2023. Полный код тут.
Код, CPU-bound задача, считаем факториалы от числа до числа:
Будем разбивать работу на 4 части, считать факториал первых 10000, потом вторых и тд. Вот так запускаем сабинтерпретаторы:
Аналогично запускаем и треды с процессами.
Результаты:
Субинтерпретаторы значительно ускорили данный пример. Работает даже быстрее FT 😱
А теперь для IO-bound задачи возьмем такой пример:
И снова
Тут может показаться, что как-то не очень много перформанса у нас получилось. Но! Вспоминаем, что внутри можно создавать дополнительные треды, чтобы еще ускорить работу. А можно даже и
Обсуждение: как вам фича?
| Поддержать | YouTube | GitHub | Чат |
- PEP: https://peps.python.org/pep-0734
- Обсуждение: https://discuss.python.org/t/pep-734-multiple-interpreters-in-the-stdlib/41147
- Документация: https://docs.python.org/3.14/library/concurrent.interpreters.html
Что оно такое?
Несколько полноценных интерпретаторов работающих рядом. Какие плюсы?
- Один процесс
- Один тред, но руками можно создавать еще
- Простые данные можно шарить без необходимости pickle, сложные нужно пиклить
- По GILу на интерпретатор, все еще можно получить плюшки настоящей многозадачности по сети
- Работает с asyncio
Минусы:
-
C код нужно было значительно переработать, не все C расширения поддерживаются (пока)Получается хорошая универсальность для разных задач.
Немного истории
Есть несколько важных нетехнических аспектов про процесс создания данной фичи:
- PEP-734 и Free-Threading делают очень похожие вещи – позволяют реализовывать настоящую многозадачность, но разными способами
- Изначально субинтерпретаторы появились в 3.10 в виде только C-шного АПИ
- Есть отдельный PyPI пакет с данным кодом
- Пайтон часть в виде PEP-734 был добавлена в 3.14 уже после feature freeze
- Изначально планировалось добавить его как модуль interpreters, однако в последний момент он стал concurrent.interpreters, вот тут доступно большое обсуждение
Как работает?
Внутри довольно много разных C-шных модулей:
- Основа: https://github.com/python/cpython/blob/main/Python/crossinterp.c
- Дефиниция модуля: https://github.com/python/cpython/blob/main/Modules/_interpretersmodule.c
- Очередь для обмена сообщениями между интерпретаторами: https://github.com/python/cpython/blob/main/Modules/_interpqueuesmodule.c
- Набор примитивов: https://github.com/python/cpython/blob/main/Modules/_interpchannelsmodule.c
Но, для пользователей - важен только питоновский АПИ, что прекрасно. Он получился простым и понятным:
interp = interpreters.create()
try:
interp.exec('print("Hello from PEP-554")')
finally:
interp.close()
Давайте посмотрим на пример и замерим!
Тестирую на M2Pro 2023. Полный код тут.
Код, CPU-bound задача, считаем факториалы от числа до числа:
def worker_cpu(arg: tuple[int, int]):
start, end = arg
fact = 1
for i in range(start, end + 1):
fact *= i
Будем разбивать работу на 4 части, считать факториал первых 10000, потом вторых и тд. Вот так запускаем сабинтерпретаторы:
from concurrent.futures import InterpreterPoolExecutor
def bench_subinterpreters():
with InterpreterPoolExecutor(CPUS) as executor:
list(executor.map(worker, WORKLOADS))
Аналогично запускаем и треды с процессами.
Результаты:
Regular: Mean +- std dev: 163 ms +- 1 ms
Threading with GIL: Mean +- std dev: 168 ms +- 2 ms
Threading NoGIL: Mean +- std dev: 48.7 ms +- 0.6 ms
Multiprocessing: Mean +- std dev: 73.4 ms +- 1.5 ms
Subinterpreters: Mean +- std dev: 44.8 ms +- 0.5 ms
Субинтерпретаторы значительно ускорили данный пример. Работает даже быстрее FT 😱
А теперь для IO-bound задачи возьмем такой пример:
def worker_io(arg: tuple[int, int]):
start, end = arg
with httpx.Client() as client:
for i in range(start, end + 1):
client.get(f'http://jsonplaceholder.typicode.com/posts/{i}')
И снова
concurrent.interpreters показывают хорошее время:
Regular: Mean +- std dev: 1.45 sec +- 0.03 sec
Threading with GIL: Mean +- std dev: 384 ms +- 17 ms (~1/4 от 1.45s)
Threading NoGIL: Mean +- std dev: 373 ms +- 20 ms
Multiprocessing: Mean +- std dev: 687 ms +- 32 ms
Subinterpreters: Mean +- std dev: 547 ms +- 13 ms
Тут может показаться, что как-то не очень много перформанса у нас получилось. Но! Вспоминаем, что внутри можно создавать дополнительные треды, чтобы еще ускорить работу. А можно даже и
asyncio так параллелить, хотя я пока и не пробовал.Обсуждение: как вам фича?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 734 – Multiple Interpreters in the Stdlib | peps.python.org
This PEP proposes to add a new module, interpreters, to support inspecting, creating, and running code in multiple interpreters in the current process. This includes Interpreter objects that represent the underlying interpreters. The module will also ...
53👍78❤21🔥13🤡4🤔2
Анонс FishITStream
(да, аллюзия на FastStream)
Мы с пацанами решили, что если и делать стримы по программированию, то сразу стримы с рыбалки. Потому что нет ничего лучше, чем говорить про программирование с рюмкой чая да на природе, глядя на озерцо.
Кто будет на связи:
– Коля Хитров — Python-блогер и серийный спикер
– Никита Пастухов — автор FastStream, галерный гребец, филантроп
– Роман Пожарнов — автор asgi-monitor, спортивный рыбак, говорит на рыбьем языке
– ну и я, конечно
О чем поговорим:
– Развитие языка Python: как развивается язык, и почему Python всё ещё лучше Go!
– Как сделать стрим из дикой природы
– Конференции и нетворкинг: зачем идти слушать и выступать, как найти тему для доклада
– Какую прикормку лучше всего брать на карася
– И, конечно же, мы не оставим без внимания OpenSource: обсудим развитие продуктов, успешные проекты, мотивацию людей и секреты правильного использования OSS
– А еще всякое про карьеру и прочее, в чем я не разбираюсь 🌚
Время: 29 июня, 12:00 МСК
Место: https://www.youtube.com/watch?v=j-XAjIlCRGg
Кстати, стрим будет на канале Коли, туда можно смело подписываться!
Надеюсь, что все получится технически.
(да, аллюзия на FastStream)
Мы с пацанами решили, что если и делать стримы по программированию, то сразу стримы с рыбалки. Потому что нет ничего лучше, чем говорить про программирование с рюмкой чая да на природе, глядя на озерцо.
Кто будет на связи:
– Коля Хитров — Python-блогер и серийный спикер
– Никита Пастухов — автор FastStream, галерный гребец, филантроп
– Роман Пожарнов — автор asgi-monitor, спортивный рыбак, говорит на рыбьем языке
– ну и я, конечно
О чем поговорим:
– Развитие языка Python: как развивается язык, и почему Python всё ещё лучше Go!
– Как сделать стрим из дикой природы
– Конференции и нетворкинг: зачем идти слушать и выступать, как найти тему для доклада
– Какую прикормку лучше всего брать на карася
– И, конечно же, мы не оставим без внимания OpenSource: обсудим развитие продуктов, успешные проекты, мотивацию людей и секреты правильного использования OSS
– А еще всякое про карьеру и прочее, в чем я не разбираюсь 🌚
Время: 29 июня, 12:00 МСК
Место: https://www.youtube.com/watch?v=j-XAjIlCRGg
Кстати, стрим будет на канале Коли, туда можно смело подписываться!
Надеюсь, что все получится технически.
2🔥109❤19👍13🤡4😢3😁2🕊2🎉1
Находки в опенсорсе
PEP-734: Subinterpreters in stdlib - PEP: https://peps.python.org/pep-0734 - Обсуждение: https://discuss.python.org/t/pep-734-multiple-interpreters-in-the-stdlib/41147 - Документация: https://docs.python.org/3.14/library/concurrent.interpreters.html Что…
PEP-734: subinterpreters и _interpqueues
Еще одной важной часть субинтерпретаторов являются очереди. Прочитать про них можно тут:
- https://peps.python.org/pep-0734/#queue-objects
- https://github.com/python/cpython/blob/main/Lib/concurrent/interpreters/_queues.py
- https://github.com/python/cpython/blob/main/Modules/_interpqueuesmodule.c
Зачем нужны очереди? Чтобы передавать объекты между интерпретаторами:
В чем важные особенности?
- Не все объекты переданные между очередями копируются. Например, immortal objects - не копируются:
-
Будьте осторожны с мутабельными буферами. Тут нужно понимать, что ты делаешь. Инструмент - очень мощный.
Больше подробностей будет в моем интервью с автором субинтерпретаторов.
- Остальные объекты копируются через
А еще есть каналы! CSP, прям как в Go: https://peps.python.org/pep-0554/#channels
Но, они пока готовы сильно меньше, чем очереди, которые уже достаточно полезные.
Но, самое главное: можно делать свои модули на C, которые будут копировать данные так, как вам нужно (или не копировать их вовсе). АПИ готовы, они работают.
Круто?
Минутка монетизации опенсорса
Часовое интервью на английском с русскими субтитрами с Eric Snow – автором субинтерпретаторов – уже на бусти. Дополнительно я вставил все примеры кода и отсылки на ПЕПы прямо в видео, чтобы было удобно смотреть и понимать, о чем мы говорим. Через неделю оно будет доступно для всех на ютюбе.
Если вы хотите поддерживать глубокий бесплатный технический контент, уникальных гостей на интервью, а так же другую мою бесплатную работу: от опенсорса до статей здесь и на хабре – есть бусти!
А еще я буду там выкладывать список ссылок на весь другой контент, который я делаю. В одном месте. Удобно!
Обсуждение: какие у вас есть варианты использования субинтерпретаторов?
| Поддержать | YouTube | GitHub | Чат |
Еще одной важной часть субинтерпретаторов являются очереди. Прочитать про них можно тут:
- https://peps.python.org/pep-0734/#queue-objects
- https://github.com/python/cpython/blob/main/Lib/concurrent/interpreters/_queues.py
- https://github.com/python/cpython/blob/main/Modules/_interpqueuesmodule.c
Зачем нужны очереди? Чтобы передавать объекты между интерпретаторами:
>>> from concurrent import interpreters
>>> interp = interpreters.create()
>>> queue = interpreters.create_queue()
>>> complex_object = [1, 'a', {'key': 'val'}, (2, 3), None, object()]
>>> complex_object # notice original id
[1, 'a', {'key': 'val'}, (2, 3), None, <object object at 0x101169ff0>]
>>> queue.put_nowait(complex_object)
>>> interp.prepare_main(queue=queue) # passing `queue` object to other interpreter
>>> interp.exec('print(queue.get_nowait())') # notice id change
[1, 'a', {'key': 'val'}, (2, 3), None, <object object at 0x101b054e0>]
В чем важные особенности?
- Не все объекты переданные между очередями копируются. Например, immortal objects - не копируются:
>>> id(12)
4308538240
>>> interp.exec('print(id(12))')
4308538240
-
memoryview (как и другие PyBuffer объекты) имеет особые гарантии. Мы передаем память прям физически. Без копирования. Потому что np.array и подобное - тоже буферы. Если бы мы копировали память буферов, то такие вычисления не отличались бы от multiprocessing, который часть по памяти имеет проблемы. Здесь – все по-другому:
>>> b = bytearray(b'123')
>>> m = memoryview(b)
>>> queue.put_nowait(m)
>>> interp.exec('(m := queue.get_nowait()); print(m); m[:] = b"456"') # changing memory directly
<memory at 0x103274940>
>>> b # was changed in another interpreter!
bytearray(b'456')
Будьте осторожны с мутабельными буферами. Тут нужно понимать, что ты делаешь. Инструмент - очень мощный.
Больше подробностей будет в моем интервью с автором субинтерпретаторов.
- Остальные объекты копируются через
pickle (пока что). В планах – ускорить и упростить данный процесс:
# ex.py
>>> class Custom:
... def __init__(self, arg: int) -> None:
... self.arg = arg
... def __getstate__(self):
... print('__getstate__')
... return {'arg': self.arg}
... def __setstate__(self, state):
... print('__setstate__', state)
... self.arg = state['arg']
# main.py
>>> from ex import Custom
>>> c = Custom(1)
>>> c
<ex.Custom object at 0x101a078c0>
>>> queue.put_nowait(c)
__getstate__
>>> interp.exec('print(queue.get_nowait())') # different object
__setstate__ {'arg': 1}
<ex.Custom object at 0x103222f20>
А еще есть каналы! CSP, прям как в Go: https://peps.python.org/pep-0554/#channels
Но, они пока готовы сильно меньше, чем очереди, которые уже достаточно полезные.
Но, самое главное: можно делать свои модули на C, которые будут копировать данные так, как вам нужно (или не копировать их вовсе). АПИ готовы, они работают.
Круто?
Минутка монетизации опенсорса
Часовое интервью на английском с русскими субтитрами с Eric Snow – автором субинтерпретаторов – уже на бусти. Дополнительно я вставил все примеры кода и отсылки на ПЕПы прямо в видео, чтобы было удобно смотреть и понимать, о чем мы говорим. Через неделю оно будет доступно для всех на ютюбе.
Если вы хотите поддерживать глубокий бесплатный технический контент, уникальных гостей на интервью, а так же другую мою бесплатную работу: от опенсорса до статей здесь и на хабре – есть бусти!
А еще я буду там выкладывать список ссылок на весь другой контент, который я делаю. В одном месте. Удобно!
Обсуждение: какие у вас есть варианты использования субинтерпретаторов?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 734 – Multiple Interpreters in the Stdlib | peps.python.org
This PEP proposes to add a new module, interpreters, to support inspecting, creating, and running code in multiple interpreters in the current process. This includes Interpreter objects that represent the underlying interpreters. The module will also ...
111🔥43❤18👍13🤡3🤯2
Находки в опенсорсе
PEP-734: subinterpreters и _interpqueues Еще одной важной часть субинтерпретаторов являются очереди. Прочитать про них можно тут: - https://peps.python.org/pep-0734/#queue-objects - https://github.com/python/cpython/blob/main/Lib/concurrent/interpreters/_queues.py…
Лучший курс по Python 15: Subinterpreters
Продолжаем говорить про субинтерпретаторы.
Пригласил их автора – Eric Snow – чтобы поговорить про историю, актуальное состояние проекта и его будущее. Особо отмечу темы про будущие оптимизации. Как ускорить старт интерпретатора? Как сделать возможным шеринг большего количества данных?
Все здесь! Есть русские и английские субтитры.
А еще я добавил много примеров кода и ссылки на исходники / пепы / статьи.
Жмите на паузу и читайте :)
https://www.youtube.com/watch?v=VBiaNNpLzWA
Внутри:
00:00 Вступление
00:11 Представление гостя
01:20 Введение в subinterpreters и PEP-554
04:21 Как subinterpreters выглядят с точки зрения OS?
05:50 Зачем добавили субинтерпретаторы в Python1.5?
08:01 Сколько субинтерпретаторов можно запустить в один момент?
09:19 История subinterpreters
17:25 Изоляция модулей и PEP-687
25:22 Immortal objects и PEP-683
29:15 Static Types
32:50 Проблема с модулем SSL
34:44 Связь subinterpreters и free-threading
42:45 Erlang и Actor Model
43:50 CSP, Channels
45:23 _interpqueues
46:11 (не)Копирование данных при отправке данных в очередь
48:53 Можно ли безопасно делить все буфферы? memoryview
49:53 subinterpreters vs multiprocessing
53:09 subinterpreters and asyncio
56:07 PEP-734
56:37 Сборщик мусора, GC
58:13 Как сделать еще быстрее и лучше в будушем?
01:03:34 Какие библиотеки стоит сделать сообществу?
01:08:14 Завершение
Обсуждение: кого бы вы хотели видеть в качестве будущего гостя?
| Поддержать | YouTube | GitHub | Чат |
Продолжаем говорить про субинтерпретаторы.
Пригласил их автора – Eric Snow – чтобы поговорить про историю, актуальное состояние проекта и его будущее. Особо отмечу темы про будущие оптимизации. Как ускорить старт интерпретатора? Как сделать возможным шеринг большего количества данных?
Все здесь! Есть русские и английские субтитры.
А еще я добавил много примеров кода и ссылки на исходники / пепы / статьи.
Жмите на паузу и читайте :)
https://www.youtube.com/watch?v=VBiaNNpLzWA
Внутри:
00:00 Вступление
00:11 Представление гостя
01:20 Введение в subinterpreters и PEP-554
04:21 Как subinterpreters выглядят с точки зрения OS?
05:50 Зачем добавили субинтерпретаторы в Python1.5?
08:01 Сколько субинтерпретаторов можно запустить в один момент?
09:19 История subinterpreters
17:25 Изоляция модулей и PEP-687
25:22 Immortal objects и PEP-683
29:15 Static Types
32:50 Проблема с модулем SSL
34:44 Связь subinterpreters и free-threading
42:45 Erlang и Actor Model
43:50 CSP, Channels
45:23 _interpqueues
46:11 (не)Копирование данных при отправке данных в очередь
48:53 Можно ли безопасно делить все буфферы? memoryview
49:53 subinterpreters vs multiprocessing
53:09 subinterpreters and asyncio
56:07 PEP-734
56:37 Сборщик мусора, GC
58:13 Как сделать еще быстрее и лучше в будушем?
01:03:34 Какие библиотеки стоит сделать сообществу?
01:08:14 Завершение
Обсуждение: кого бы вы хотели видеть в качестве будущего гостя?
| Поддержать | YouTube | GitHub | Чат |
YouTube
Лучший курс по Python 15: Subinterpreters
Лучший курс по питону: 15
Или "обзор исходников CPython с CPython core разработчиком".
Тема: Subinterpreters
Гость: Eric Snow https://github.com/ericsnowcurrently
00:00 Вступление
00:11 Представление гостя
01:20 Введение в subinterpreters и PEP-554
04:21…
Или "обзор исходников CPython с CPython core разработчиком".
Тема: Subinterpreters
Гость: Eric Snow https://github.com/ericsnowcurrently
00:00 Вступление
00:11 Представление гостя
01:20 Введение в subinterpreters и PEP-554
04:21…
19🔥136❤21👍19💩2🤡2🥰1
PEP-797: Иммортализация произвольных объектов
- Ссылка на черновик PEP: https://github.com/python/peps/pull/4497
- Оригинальный PEP-683 с Immortal объектами: https://peps.python.org/pep-0683
Продолжаем про будущее субинтерпретаторов! Да, что-то меня увлекла данная тема :)
Как делиться объектами без копирования данных в субинтерпретаторах?
Чтобы легко делиться объектами между субинтерпретаторами, необходимо, чтобы они были полностью иммутабельными. Полностью. Не с точки зрения питона, а с точки зрения C.
Даже если вы будете делиться объектами, которые внешне нельзя изменить, то все еще будет один очень важный нюанс.
Напомню, что объект питона с точки зрения C выглядит так (упрощенно):
И вот тот самый
Следовательно, мы можем словить гонку данных.
Чтобы гонки не было, мы не должны менять
Что такое вообще Immortal объекты?
Ровно как я и писал выше – объекты, которые не участвуют в подсчете ссылок и живут, пока программа не завершится. Что-то вроде
Внутри питона есть несколько мест, которые нам интересны с данной точки зрения:
То есть – объект
И вот почему:
Когда объект "immortal", то с ним и не нужно проводить никаких доп операций.
Как предлагается делать свои?
Все! Теперь объект
Поверх такого АПИ, скорее всего, будет какое-то красивое АПИ. Нужно будет следить, чтобы бессмертные объекты не были слишком большими / их не было слишком много. Ну и подготовить их логически тоже необходимо.
Итого: иммутабельные объекты, субинтерпретаторы, полная параллельность. Да у нас, что, Erlang?!
Обсуждение: как вам данная фича?
| Поддержать | YouTube | GitHub | Чат |
- Ссылка на черновик PEP: https://github.com/python/peps/pull/4497
- Оригинальный PEP-683 с Immortal объектами: https://peps.python.org/pep-0683
Продолжаем про будущее субинтерпретаторов! Да, что-то меня увлекла данная тема :)
Как делиться объектами без копирования данных в субинтерпретаторах?
Чтобы легко делиться объектами между субинтерпретаторами, необходимо, чтобы они были полностью иммутабельными. Полностью. Не с точки зрения питона, а с точки зрения C.
Даже если вы будете делиться объектами, которые внешне нельзя изменить, то все еще будет один очень важный нюанс.
Напомню, что объект питона с точки зрения C выглядит так (упрощенно):
struct PyObject {
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
};
И вот тот самый
ob_refcnt все время меняется. Буквально в любом C коде все время вызовы Py_DECREF и Py_INCREF. Без изменения счетчика ссылок невозможно выполнить никакой код. И буквально все части питона содержат вызовы, которые уменьшают или увеличивают счетчик ссылок во время работы программы. Следовательно, мы можем словить гонку данных.
Чтобы гонки не было, мы не должны менять
ob_refcnt. А чтобы его не менять, нам нужно, чтобы объект был бессмертным: жил на протяжении всего времени жизни программы и потом был правильно собран.Что такое вообще Immortal объекты?
Ровно как я и писал выше – объекты, которые не участвуют в подсчете ссылок и живут, пока программа не завершится. Что-то вроде
static в C и 'static в Rust.Внутри питона есть несколько мест, которые нам интересны с данной точки зрения:
#define _Py_IMMORTAL_REFCNT_LOCAL UINT32_MAX
То есть – объект
Immortal, когда у него просто очень большой refcnt. Что легко проверить:
>>> import sys
>>> sys.getrefcount(None)
3221225472
>>> x = None # он не будет меняться при создании новых имен:
>>> sys.getrefcount(None)
3221225472
И вот почему:
static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
{
if (_Py_IsImmortal(op)) {
_Py_INCREF_IMMORTAL_STAT_INC();
return;
}
op->ob_refcnt++;
}
static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
{
if (_Py_IsImmortal(op)) {
return;
}
if (--op->ob_refcnt == 0) {
_Py_Dealloc(op);
}
}
Когда объект "immortal", то с ним и не нужно проводить никаких доп операций.
Как предлагается делать свои?
import sys
admin = User('admin')
sys._immortalize(admin)
assert sys._is_immortal(admin)
Все! Теперь объект
admin будет жить до конца программы. И его можно будет использовать в разных субинтерпретаторах без копирования:
>>> from concurrent import interpreters
>>> interp = interpreters.create()
>>> interp.prepare_main(admin=admin)
>>> interp.exec('print(admin)')
'<User: admin>'
Поверх такого АПИ, скорее всего, будет какое-то красивое АПИ. Нужно будет следить, чтобы бессмертные объекты не были слишком большими / их не было слишком много. Ну и подготовить их логически тоже необходимо.
Итого: иммутабельные объекты, субинтерпретаторы, полная параллельность. Да у нас, что, Erlang?!
Обсуждение: как вам данная фича?
| Поддержать | YouTube | GitHub | Чат |
GitHub
PEP 797: Arbitrary Object Immortalization by ZeroIntensity · Pull Request #4497 · python/peps
Basic requirements (all PEP Types)
Read and followed PEP 1 & PEP 12
File created from the latest PEP template
PEP has next available number, & set in filename (pep-NNNN.rst), PR...
Read and followed PEP 1 & PEP 12
File created from the latest PEP template
PEP has next available number, & set in filename (pep-NNNN.rst), PR...
1❤60👍32🔥11🤔6💩3🕊3🤡3😁1🤯1
Снимок экрана 2025-07-25 в 16.38.01.png
454.8 KB
Делаем бесплатный курс по vscode?
Довольно часто последнее время наблюдаю, как программируют другие люди. На собесах в своем окружении, в паре со мной, на ютюбе и тд. И вот что я замечаю. Очень много людей страдает от базовых вещей, которые можно сделать простыми и удобными. Я хочу помочь.
Тем более видосы с нарезкой моего подкаста на данную тему с @t0digital собрали много обсуждений и даже возмущений. А значит – тема горячая :)
Будем делать из второй картинки третью.
О чем поговорим?
- Почему DX важен?
- Почему vscode, а не vim / pycharm / emacs / тд. И как применить такие же подходы к другим средам
- О минимализме. Для успешной работы вам нужно меньше инструментов, а не больше
- О том, как сделать минимальное количество полезных горячих клавиш, которыми вы реально будете пользоваться
- Как навигироваться по коду, файлам, важным местам в проекте
- Какие принципы позволят вам сделать свой уникальный рабочий сетап, который удобен вам
- Как можно делать свои крутые инструменты, как пример для работы со сложными кейсами в git: https://github.com/sobolevn/fzf-simple-git
- Как писать свои темы, плагины. И когда их не писать
Будет крайне полезно, чтобы писать код быстрее и проще.
Мои конфиги за ~10 лет работы всегда можно посмотреть тут: https://github.com/sobolevn/dotfiles
Собираем донат goal на +16 человек – и начинаем! Все будет бесплатно и на ютюбе. Подписка на https://boosty.to/sobolevn стартует со 100 рублей.
Холивар про IDE объявляется открытым в комментах 🌚
Довольно часто последнее время наблюдаю, как программируют другие люди. На собесах в своем окружении, в паре со мной, на ютюбе и тд. И вот что я замечаю. Очень много людей страдает от базовых вещей, которые можно сделать простыми и удобными. Я хочу помочь.
Тем более видосы с нарезкой моего подкаста на данную тему с @t0digital собрали много обсуждений и даже возмущений. А значит – тема горячая :)
Будем делать из второй картинки третью.
О чем поговорим?
- Почему DX важен?
- Почему vscode, а не vim / pycharm / emacs / тд. И как применить такие же подходы к другим средам
- О минимализме. Для успешной работы вам нужно меньше инструментов, а не больше
- О том, как сделать минимальное количество полезных горячих клавиш, которыми вы реально будете пользоваться
- Как навигироваться по коду, файлам, важным местам в проекте
- Какие принципы позволят вам сделать свой уникальный рабочий сетап, который удобен вам
- Как можно делать свои крутые инструменты, как пример для работы со сложными кейсами в git: https://github.com/sobolevn/fzf-simple-git
- Как писать свои темы, плагины. И когда их не писать
Будет крайне полезно, чтобы писать код быстрее и проще.
Мои конфиги за ~10 лет работы всегда можно посмотреть тут: https://github.com/sobolevn/dotfiles
Собираем донат goal на +16 человек – и начинаем! Все будет бесплатно и на ютюбе. Подписка на https://boosty.to/sobolevn стартует со 100 рублей.
Холивар про IDE объявляется открытым в комментах 🌚
53👍257❤54🔥47👎9🤡4💩3👏2😱1👌1🕊1