PEP-661: sentinel объекты
PEP: https://peps.python.org/pep-0661/
Код: https://github.com/python/cpython/pull/148831
Обсуждение: https://discuss.python.org/t/pep-661-sentinel-values/9126
В питон 3.15 добавляют новый
Проблема достаточно понятная, например: нам нужно создать какое-то значение по-умолчанию, чтобы мы знали, что аргумент не был передан. Но
Данная логика встречается буквально везде:
• dataclasses
• django_modern_rest
• msgspec (тоже самое но на C)
Однако, теперь можно упростить АПИ для создания таких объектов до:
А вот пример PR, где в
Как оно примерно внутри устроено
Как и все билтины,
Но я приведу примерную версию на питоне (из PEP), чтобы было понятнее, как он работает внутри:
Хороший пример синглтона ^
Что здесь важно?
1.
2. Объект должны быть внешне иммутабельным
3. Копирование объекта должно возвращать тот же самый синглтон
Не только для Питона
Ну и конечно же: есть две новые функции в C-API для создания таких объектов в C-extensions (как
•
•
Вот такая фича. Довольно просто, закрывает понятную проблему. Но не очень ясно, почему builtin.
Обсуждение: Приходилось ли пользоваться чем-то подобным? Какую реализацию синглтона в питоне вы считаете лучшей? Согласны с добавлением нового builtin?
| Поддержать | YouTube | GitHub | Чат |
PEP: https://peps.python.org/pep-0661/
Код: https://github.com/python/cpython/pull/148831
Обсуждение: https://discuss.python.org/t/pep-661-sentinel-values/9126
В питон 3.15 добавляют новый
builtin – sentinel, чтобы создавать значения по-умолчанию.Проблема достаточно понятная, например: нам нужно создать какое-то значение по-умолчанию, чтобы мы знали, что аргумент не был передан. Но
None является валидным значением в нашей логике. Потому нужно создать новое особое "пустое" значение.Данная логика встречается буквально везде:
• dataclasses
• django_modern_rest
• msgspec (тоже самое но на C)
Однако, теперь можно упростить АПИ для создания таких объектов до:
_SENTINEL_VALUE = sentinel('_SENTINEL_VALUE')
А вот пример PR, где в
dataclasses уже используют новое АПИ: https://github.com/python/cpython/commit/16952218d0535904236e8a39851133688c9ce1f0Как оно примерно внутри устроено
Как и все билтины,
sentinel написан на C, его исходники вот тут: https://github.com/python/cpython/blob/main/Objects/sentinelobject.cНо я приведу примерную версию на питоне (из PEP), чтобы было понятнее, как он работает внутри:
class sentinel:
__slots__ = ("__name__", "_module_name")
def __init_subclass__(cls):
raise TypeError("type 'sentinel' is not an acceptable base type")
def __init__(self, name, /):
if not isinstance(name, str):
raise TypeError("sentinel name must be a string")
self.__name__ = name
self._module_name = sys._getframemodulename(1)
@property
def __module__(self):
return self._module_name
def __repr__(self):
return self.__name__
def __reduce__(self):
return self.__name__
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
def __or__(self, other):
return typing.Union[self, other]
Хороший пример синглтона ^
Что здесь важно?
1.
pickle должен корректно работать, для того имя sentinel('NAME') должно совпадать с именем объекта на уровне модуля: NAME = 2. Объект должны быть внешне иммутабельным
3. Копирование объекта должно возвращать тот же самый синглтон
Не только для Питона
Ну и конечно же: есть две новые функции в C-API для создания таких объектов в C-extensions (как
msgspec например): •
PyObject *PySentinel_New(const char *name, const char *module_name) для создания•
bool PySentinel_Check(PyObject *obj) для проверкиВот такая фича. Довольно просто, закрывает понятную проблему. Но не очень ясно, почему builtin.
Обсуждение: Приходилось ли пользоваться чем-то подобным? Какую реализацию синглтона в питоне вы считаете лучшей? Согласны с добавлением нового builtin?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 661 – Sentinel Values | peps.python.org
Unique placeholder values, commonly known as “sentinel values”, are common in programming. They have many uses, such as for:
2👍57❤8🔥8🤔2🤯1
Вышел mypy 2.0
Changelog: https://github.com/python/mypy/blob/master/CHANGELOG.md#mypy-20
Что изменилось?
По-умолчанию
Включили
Теперь можно переопределять переменные, даже разных типов с
Данная фича раньше была под флагом
Самое интересное
Добавили
Против режима с одним воркером (как было до 2.0):
А теперь еще убираем
Вот такой прирост производительности. Версия с
Очень радостно, что mypy становится быстрее. Дальнейшее развитие mypyc приведет к еще большему перфу. И не только для mypy.
Обсуждение: Как быстро вы обновляете mypy на своих проектах? Насколько сурово настраиваете? Будет ли профит от нескольких воркеров?
| Поддержать | YouTube | GitHub | Чат |
Changelog: https://github.com/python/mypy/blob/master/CHANGELOG.md#mypy-20
Что изменилось?
По-умолчанию
--local-partial-types теперь всегда включен. Он нужен для корректной типизации в разных скоупах.
a = [] # Needs type annotation when using `local-partial-types`
def func() -> None:
a.append(1)
Включили
--strict-bytes по-умолчанию. Раньше тип bytes разрешал передавать memoryview и bytearray. Теперь с новым поведением bytes разрешает только bytes, все остальные типы нужно указывать отдельно.Теперь можно переопределять переменные, даже разных типов с
--allow-redefinition
def foo(cond: bool) -> None:
if cond:
for x in ["a", "b"]:
# Type of "x" is "str" here
...
else:
for x in [1, 2]:
# Type of "x" is "int" here
...
Данная фича раньше была под флагом
--allow-redefinition-new, а теперь включена по-умолчанию.Самое интересное
Добавили
--num-workers, который позволяет ускорить mypy кратно на больших кодовых базах. Я буду запускать mypy прямо на кодовой базе mypy (без mypyc, без кеша, но с orjson и `sqlite_cache`):
» rm -rf .mypy_cache && time mypy --config-file mypy_self_check.ini -p mypy -p mypyc --num-workers=8
7.090 total
Против режима с одним воркером (как было до 2.0):
» rm -rf .mypy_cache && time mypy --config-file mypy_self_check.ini -p mypy -p mypyc
25.335 total
А теперь еще убираем
orjson и sqlite_cache:
» rm -rf .mypy_cache && time mypy --config-file mypy_self_check.ini -p mypy -p mypyc
28.108 total
Вот такой прирост производительности. Версия с
mypyc (то есть та, которую мы скачиваем из pip) будет еще быстрее.Очень радостно, что mypy становится быстрее. Дальнейшее развитие mypyc приведет к еще большему перфу. И не только для mypy.
Обсуждение: Как быстро вы обновляете mypy на своих проектах? Насколько сурово настраиваете? Будет ли профит от нескольких воркеров?
| Поддержать | YouTube | GitHub | Чат |
GitHub
mypy/CHANGELOG.md at master · python/mypy
Optional static typing for Python. Contribute to python/mypy development by creating an account on GitHub.
1🔥76👍22❤7🙏1
Находки в опенсорсе: хлеб
> The sourdough framework is an open-source book dedicated to helping you to make the best possible sourdough bread at home.
https://github.com/hendricius/the-sourdough-framework
Наконец-то нормальные проекты!
Люблю домашний хлеб. Делимся рецептами вкусной еды / хлеба в комментах!
> The sourdough framework is an open-source book dedicated to helping you to make the best possible sourdough bread at home.
https://github.com/hendricius/the-sourdough-framework
Наконец-то нормальные проекты!
Люблю домашний хлеб. Делимся рецептами вкусной еды / хлеба в комментах!
2🔥106❤21🥰9😁4😱2🤯1🎉1
ИИ переписал Bun с Zig на Rust
PR: https://github.com/oven-sh/bun/pull/30412 (он настолько большой, что гитхаб его не открывает у меня)
Последние несколько дней в чате очень плотно обсуждали последнюю ИИ новость.
Один из альтернативных JS рантаймов bun полность переписали с zig на #rust.
Переписывали, конечно же, используя исключительно агентов и ИИ (от компании Anthropic) .
На все про все ушло 10 дней, тесты прошли, перформанс остался такой же.
Звучит красиво? Красиво.
Таймлайн истории
1. 2 декабря 2025 года Anthropic покупает bun и всю команду: https://bun.com/blog/bun-joins-anthropic
2. Команда Zig известна своим "No AI Slop" policy (прямо как django-modern-rest), некоторые люди сразу предсказывали конфликт интересов между Bun + Anthropic и Zig
3. 26 апреля 2026 года, команда bun форкает zig и добавляет туда поддержку параллельного семантического анализа https://x.com/bunjavascript/status/2048427636414923250
4. 9 мая открывается тот самый PR
5. 14 мая он успешно смерджен
Важные детали
А вот тут начинается интересное.
- Для начала авторы Zig объяснили, что подход форка с семаналом некорректный, и что они сами работают над данной фичей, скоро она будет доступна: https://ziggit.dev/t/bun-s-zig-fork-got-4x-faster-compilation-times/15183/19
- Билды получились недетерминированные, о чем им и рассказала кор-команда. Тогда форк пришлось закопать, видимо
Теперь посмотрим на качество PR.
- Качество кода там примерно вот такое: https://github.com/oven-sh/bun/commit/d144fa6e20ab65d55add82ef3241609dcbb04cdc (то есть - никакое)
- Файлы в нем даже были неотформатированы встроенным
- Ревью не было, потому что внутри PRа
-
- "Скорость работы осталось такой же" - довольно странный тезис, учитывая что zig и rust оба генерят код через LLVM, часто практически идентичный, заслуги ИИ здесь нет
Выводы
- Прикольно, что такое вообще можно сделать (с неограниченными токенами)
- Как теперь bun будет владеть своей базой кода, кто сможет в ней разобраться и что-то пофиксить - вопрос открытый
- Какой смысл во всем действии (кроме очевидного маркетинга) - вопрос открытый
- Брать ли теперь bun в прод? Конечно нет
Обсуждение: что вы думаете по данному вопросу? Стали бы использовать bun у себя в проекте в новом виде?
| Поддержать | YouTube | GitHub | Чат |
PR: https://github.com/oven-sh/bun/pull/30412 (он настолько большой, что гитхаб его не открывает у меня)
Последние несколько дней в чате очень плотно обсуждали последнюю ИИ новость.
Один из альтернативных JS рантаймов bun полность переписали с zig на #rust.
Переписывали, конечно же, используя исключительно агентов и ИИ (от компании Anthropic) .
На все про все ушло 10 дней, тесты прошли, перформанс остался такой же.
Звучит красиво? Красиво.
Таймлайн истории
1. 2 декабря 2025 года Anthropic покупает bun и всю команду: https://bun.com/blog/bun-joins-anthropic
2. Команда Zig известна своим "No AI Slop" policy (прямо как django-modern-rest), некоторые люди сразу предсказывали конфликт интересов между Bun + Anthropic и Zig
3. 26 апреля 2026 года, команда bun форкает zig и добавляет туда поддержку параллельного семантического анализа https://x.com/bunjavascript/status/2048427636414923250
4. 9 мая открывается тот самый PR
5. 14 мая он успешно смерджен
Важные детали
А вот тут начинается интересное.
- Для начала авторы Zig объяснили, что подход форка с семаналом некорректный, и что они сами работают над данной фичей, скоро она будет доступна: https://ziggit.dev/t/bun-s-zig-fork-got-4x-faster-compilation-times/15183/19
- Билды получились недетерминированные, о чем им и рассказала кор-команда. Тогда форк пришлось закопать, видимо
Теперь посмотрим на качество PR.
- Качество кода там примерно вот такое: https://github.com/oven-sh/bun/commit/d144fa6e20ab65d55add82ef3241609dcbb04cdc (то есть - никакое)
- Файлы в нем даже были неотформатированы встроенным
cargo fmt, что делается буквально в каждом Rust проекте: https://github.com/oven-sh/bun/pull/30695- Ревью не было, потому что внутри PRа
+1 009 257, -4 024 и 6000+ коммитов-
unsafe в коде встречает 10487 раз (да, там много ffi, но все равно). Для сравнения в uv (кода правда меньше в 2 раза) - всего 73 раза- "Скорость работы осталось такой же" - довольно странный тезис, учитывая что zig и rust оба генерят код через LLVM, часто практически идентичный, заслуги ИИ здесь нет
Выводы
- Прикольно, что такое вообще можно сделать (с неограниченными токенами)
- Как теперь bun будет владеть своей базой кода, кто сможет в ней разобраться и что-то пофиксить - вопрос открытый
- Какой смысл во всем действии (кроме очевидного маркетинга) - вопрос открытый
- Брать ли теперь bun в прод? Конечно нет
Обсуждение: что вы думаете по данному вопросу? Стали бы использовать bun у себя в проекте в новом виде?
| Поддержать | YouTube | GitHub | Чат |
GitHub
Rewrite Bun in Rust by Jarred-Sumner · Pull Request #30412 · oven-sh/bun
Blog post with details coming soon.
It passes Bun's pre-existing test suite on all platforms (and fixes several memory leaks and flaky tests), the binary size shrinks by 3 MB - 8 MB, the be...
It passes Bun's pre-existing test suite on all platforms (and fixes several memory leaks and flaky tests), the binary size shrinks by 3 MB - 8 MB, the be...
1👍74😁64❤19💩14🤯11🤔6🤡3🔥2👎1
Free-Threading и итераторы: что могло пойти так?
Недавно в питоне появилась новая фича (которую я вам пока не покажу), а я решил сделать новый формат – вопрос-загадку.
Мы все знаем, что Free-Threading работает совсем по-другому, вместо одного глобального GIL, у нас множество критических секций per-object и атомарных операций.
Тут обычный питоновский код на тредах. Создаем 10 тредов и идем по итератору, складываем его объекты в одну общую сумму с локом. В итоге должно получиться значение равное
Перед запуском подумайте сначала сами:
- Что вообще может произойти?
- Как поправить текущую ситуацию в теории?
- Как можно поменять код сейчас без каких-либо новых фичей, чтоб заработало?
- Что было бы идеально увидеть в качестве решения из коробки?
- Где бы вы хотели увидеть такое решение в модулях питона?
Ответ и ссылки будут вечером. В комментах - обсуждаем!
| Поддержать | YouTube | GitHub | Чат |
Недавно в питоне появилась новая фича (которую я вам пока не покажу), а я решил сделать новый формат – вопрос-загадку.
Мы все знаем, что Free-Threading работает совсем по-другому, вместо одного глобального GIL, у нас множество критических секций per-object и атомарных операций.
Тут обычный питоновский код на тредах. Создаем 10 тредов и идем по итератору, складываем его объекты в одну общую сумму с локом. В итоге должно получиться значение равное
sum(range(limit)). Получится ли?
import threading
import time
from test.support import threading_helper
limit = 10_000
workers_count = 10
result = 0
result_lock = threading.Lock()
start = threading.Event()
def producer(limit):
for x in range(limit):
yield x
def consumer(iterator):
global result
start.wait()
total = 0
for x in iterator:
total += x
with result_lock:
result += total
iterator = producer(limit) # 🤔
workers = [
threading.Thread(target=consumer, args=(iterator,))
for _ in range(workers_count)
]
with threading_helper.wait_threads_exit():
for worker in workers:
worker.start()
for worker in workers:
# Wait for the worker thread to actually start.
while worker.ident is None:
time.sleep(0.1)
start.set()
for worker in workers:
worker.join()
Перед запуском подумайте сначала сами:
- Что вообще может произойти?
- Как поправить текущую ситуацию в теории?
- Как можно поменять код сейчас без каких-либо новых фичей, чтоб заработало?
- Что было бы идеально увидеть в качестве решения из коробки?
- Где бы вы хотели увидеть такое решение в модулях питона?
Ответ и ссылки будут вечером. В комментах - обсуждаем!
| Поддержать | YouTube | GitHub | Чат |
GitHub
sobolevn - Overview
sobolevn has 640 repositories available. Follow their code on GitHub.
❤20👍15🤔9🤡2👎1😁1🤯1😢1
Находки в опенсорсе
Free-Threading и итераторы: что могло пойти так? Недавно в питоне появилась новая фича (которую я вам пока не покажу), а я решил сделать новый формат – вопрос-загадку. Мы все знаем, что Free-Threading работает совсем по-другому, вместо одного глобального…
Настало время ответов!
Во-первых
Код из примера упадет с
Почему так? Нельзя дважды запустить один и тот же генератор, даже в одном треде.
Самый простой пример:
Исходник:
Во-вторых
Переиспользовать генераторы в разных тредах - особенно плохая идея. О чем теперь явно написано в документации. Данный паттерн не поддерживается во Free-Threading нативно. Корневая причина, для самых любопытных: https://github.com/python/cpython/issues/120496
PR: https://github.com/python/cpython/pull/148894
Документация: https://docs.python.org/3.15/library/threading.html#iterator-synchronization
Был добавлен способ вызова
Для того, чтобы код из оригинального примера заработал, нужно заменить
Теперь - должно быть понятно, почему такая фича была добавлена.
Было ли интересно поковырять? Было ли сложно? :)
Во-первых
Код из примера упадет с
ValueError: generator already executing.Почему так? Нельзя дважды запустить один и тот же генератор, даже в одном треде.
Самый простой пример:
def g():
i = next(me)
yield i
me = g()
next(me) # ValueError
Исходник:
static PySendResult // Objects/genobject.c
gen_send_ex(PyGenObject *gen, PyObject *arg, PyObject **presult)
{
int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state);
// ...
if (frame_state == FRAME_EXECUTING) {
PyErr_SetString(PyExc_ValueError, "generator already executing");
return PYGEN_ERROR;
}
// ...
}
Во-вторых
Переиспользовать генераторы в разных тредах - особенно плохая идея. О чем теперь явно написано в документации. Данный паттерн не поддерживается во Free-Threading нативно. Корневая причина, для самых любопытных: https://github.com/python/cpython/issues/120496
PR: https://github.com/python/cpython/pull/148894
Документация: https://docs.python.org/3.15/library/threading.html#iterator-synchronization
Был добавлен способ вызова
__next__ под локом (как правильно догадались в комментариях):
class serialize_iterator:
def __init__(self, iterable):
self._iterator = iter(iterable)
self._lock = Lock()
def __iter__(self):
return self
def __next__(self):
with self._lock:
return next(self._iterator)
Для того, чтобы код из оригинального примера заработал, нужно заменить
iterator = producer(limit) на iterator = threading.serialize_iterator(producer(limit)). Есть еще декоратор @synchronized_iterator для определения threadsafe генераторов сразу.Теперь - должно быть понятно, почему такая фича была добавлена.
Было ли интересно поковырять? Было ли сложно? :)
GitHub
Sequence iterator thread-safety · Issue #120496 · python/cpython
Bug report Bug description: Sequence iterators are not thread-safe under the free-threaded build. They'll sometimes be accessed with the same index. Here is a minimal repro: import concurrent.f...
👍68🔥19🤯9❤3🎉1
Находки в опенсорсе
PEP 810: Explicit lazy imports На обсуждение вышел новый PEP, который предлагает добавить в Python 3.15 новый вид импортов. https://peps.python.org/pep-0810/ lazy import json lazy from json import dumps Как будет работать? Импорты не будут подгружаться…
PEP 810: Explicit lazy imports 2
Как я уже писал, в Python 3.15 нас ждут lazy imports.
В первом посте я описал основные фичи. Прочитайте его перед продолжением.
Во втором посте настало время посмотреть на плохие части.
Детали PEP, которые мы не осветили прошлый раз
Во-первых, из очевидного:
Во-вторых, я не уточнил, как будет работать
Мы можем указывать
Ну и самое забавное, мы можем управлять глобальным стейтом всех импортов через
Внедрение в питон
В stdlib питона уже активно используют lazy импорты. Однако, внутри уже появились циклические импорты. Потому что теперь так можно сделать случайно. И специально. Да, ленивые импорты могут помогать избегать циклических импортов. В некоторых режимах работы.
Теперь stdlib больше не работает в режиме
О чем развернулась жаркая дискуссия, прочитать которую я всем советую: https://github.com/python/cpython/issues/149321
Но и режим
Так как импорт становится ленивым, он больше не проверяет есть ли на самом деле библиотека
Вот в такой ситуации мы все оказались. Зато теперь некоторые скрипты будут запускаться быстрее, потому что импорты в некоторых местах стали ленивыми. Иногда, не точно. Почему нельзя было использовать импорт внутри функции? Я не знаю.
Мое отношение к данной фиче можно только охарактеризовать словами вечного инструмента
Обсуждение: я даже не знаю, честно. Давайте просто обнимемся в комментах.
| Поддержать | YouTube | GitHub | Чат |
Как я уже писал, в Python 3.15 нас ждут lazy imports.
В первом посте я описал основные фичи. Прочитайте его перед продолжением.
Во втором посте настало время посмотреть на плохие части.
Детали PEP, которые мы не осветили прошлый раз
Во-первых, из очевидного:
lazy import может быть использован только на уровне модуля, в других местах - он будет вызывать ошибку синтаксиса. Но, что забавно, lazy import не может быть использован внутри даже try блоков.Во-вторых, я не уточнил, как будет работать
__lazy_modules__, а там дичь.Мы можем указывать
__lazy_modules__ = ['os', 'typing'] в любой версии питона. Очевидно, что работать как ленивые они будут только в 3.15+, в остальных - будет просто неиспользуемый атрибут. Но штука в том, что в разных версиях питона библиотеки будут работать по-разному. Но! Он будет ленивым, только если он может быть ленивым. То есть, если он находится внутри класса, функции, try, тд - он не станет ленивым. Удачи в дебаге, короче.Ну и самое забавное, мы можем управлять глобальным стейтом всех импортов через
-X lazy_imports=none|normal|all и так же через переменную окружения PYTHON_LAZY_IMPORTS. Что оно значит? Отключаем все lazy импорты | все работает так, как написано | все импорты ленивые. Мы можем управлять тем, как работают импорты через переменную окружения!! Перечитайте, если вы тоже не поняли. Я вот не сразу понял.Внедрение в питон
В stdlib питона уже активно используют lazy импорты. Однако, внутри уже появились циклические импорты. Потому что теперь так можно сделать случайно. И специально. Да, ленивые импорты могут помогать избегать циклических импортов. В некоторых режимах работы.
Теперь stdlib больше не работает в режиме
-X lazy_imports=none.О чем развернулась жаркая дискуссия, прочитать которую я всем советую: https://github.com/python/cpython/issues/149321
Но и режим
-X lazy_imports=all все сломал. Теперь с ним некоторые библиотеки начали работать по-другому. Например:
$ PYTHON_LAZY_IMPORTS=normal ./python -c "import shutil; print(shutil._BZ2_SUPPORTED)"
False
$ PYTHON_LAZY_IMPORTS=all ./python -c "import shutil; print(shutil._BZ2_SUPPORTED)"
True
Так как импорт становится ленивым, он больше не проверяет есть ли на самом деле библиотека
_bz2 у вас. А просто всегда возвращает True. Что делать - пока никто не знает: https://github.com/python/cpython/issues/150167Вот в такой ситуации мы все оказались. Зато теперь некоторые скрипты будут запускаться быстрее, потому что импорты в некоторых местах стали ленивыми. Иногда, не точно. Почему нельзя было использовать импорт внутри функции? Я не знаю.
Мое отношение к данной фиче можно только охарактеризовать словами вечного инструмента
wemake-python-styleguide: https://github.com/wemake-services/wemake-python-styleguide/issues/3639Обсуждение: я даже не знаю, честно. Давайте просто обнимемся в комментах.
| Поддержать | YouTube | GitHub | Чат |
Telegram
Находки в опенсорсе
PEP 810: Explicit lazy imports
На обсуждение вышел новый PEP, который предлагает добавить в Python 3.15 новый вид импортов.
https://peps.python.org/pep-0810/
lazy import json
lazy from json import dumps
Как будет работать?
Импорты не будут подгружаться…
На обсуждение вышел новый PEP, который предлагает добавить в Python 3.15 новый вид импортов.
https://peps.python.org/pep-0810/
lazy import json
lazy from json import dumps
Как будет работать?
Импорты не будут подгружаться…
1😁50❤24🔥8🤯6👏4🕊4😱3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Анонс стрима: "работаем над lazy import'ами в CPython и плачем под аниме"
(на превью - я на стриме)
Мы с @nkhitrov_blog, @fastnewsdev и Денисом Аникиным (в 2026 и без тг канала!) решили замутить стрим по питону и ... новый канал на ютюбе под названием "Вялые Питоны".
Подписаться уже можно вот тут: https://www.youtube.com/@SluggishPythons
О чем будет канал?
- Менее душный и более мемный чем мой основной
- Все еще про питон и всякие хардкорные штуки внутри
- Шутки, пиво, лень, слезы
- Разные новые форматы, которые мы будем анонсировать постепенно
- Разные интересные коллабы с веселыми и умными людьми
Контент на старом канале останется таким же, каким и был. Я как раз вернулся из творческого отпуска. Скоро будет завоз по adaptix и django-modern-rest. И финал по vscode.
О чем будет первый стрим?
- Обсудим мотивацию и устройство PEP-810, потестим разные странные случае, Никита побомбит
- Я запилю каких-нибудь пару тасочек в CPython, например https://github.com/python/cpython/issues/150459
- Если я буду плохо рассказывать, что там происходят - пацаны будут меня душить своими любимыми аниме
- Если хватит времени, то еще починим setuptools / distutils, а то я все сломал
- Выпьем пива со всеми желающими 🍻
Народ в чате проголосовал за время стрима в будний вечер, так что - записываем дату и время:
Среда, 3 июня, 19:00
https://www.youtube.com/watch?v=W9Hd5dfxjIU
Приходите задавать свои ответы и хорошо проводить время!
(на превью - я на стриме)
Мы с @nkhitrov_blog, @fastnewsdev и Денисом Аникиным (в 2026 и без тг канала!) решили замутить стрим по питону и ... новый канал на ютюбе под названием "Вялые Питоны".
Подписаться уже можно вот тут: https://www.youtube.com/@SluggishPythons
О чем будет канал?
- Менее душный и более мемный чем мой основной
- Все еще про питон и всякие хардкорные штуки внутри
- Шутки, пиво, лень, слезы
- Разные новые форматы, которые мы будем анонсировать постепенно
- Разные интересные коллабы с веселыми и умными людьми
Контент на старом канале останется таким же, каким и был. Я как раз вернулся из творческого отпуска. Скоро будет завоз по adaptix и django-modern-rest. И финал по vscode.
О чем будет первый стрим?
- Обсудим мотивацию и устройство PEP-810, потестим разные странные случае, Никита побомбит
- Я запилю каких-нибудь пару тасочек в CPython, например https://github.com/python/cpython/issues/150459
- Если я буду плохо рассказывать, что там происходят - пацаны будут меня душить своими любимыми аниме
- Если хватит времени, то еще починим setuptools / distutils, а то я все сломал
- Выпьем пива со всеми желающими 🍻
Народ в чате проголосовал за время стрима в будний вечер, так что - записываем дату и время:
Среда, 3 июня, 19:00
https://www.youtube.com/watch?v=W9Hd5dfxjIU
Приходите задавать свои ответы и хорошо проводить время!
10🔥85😁29❤12👍5💩4🕊1
Находки в опенсорсе
Анонс стрима: "работаем над lazy import'ами в CPython и плачем под аниме" (на превью - я на стриме) Мы с @nkhitrov_blog, @fastnewsdev и Денисом Аникиным (в 2026 и без тг канала!) решили замутить стрим по питону и ... новый канал на ютюбе под названием "Вялые…
YouTube
Работаем над lazy import'ами в CPython и плачем под аниме
О чем будет первый стрим?
- Обсудим мотивацию и устройство PEP-810, потестим разные странные случае, Никита побомбит
- Я запилю каких-нибудь пару тасочек в CPython
- Если я буду плохо рассказывать, что там происходят - пацаны будут меня душить своими любимыми…
- Обсудим мотивацию и устройство PEP-810, потестим разные странные случае, Никита побомбит
- Я запилю каких-нибудь пару тасочек в CPython
- Если я буду плохо рассказывать, что там происходят - пацаны будут меня душить своими любимыми…
5❤32🔥21💩2🕊1
Находки в опенсорсе
Анонс стрима: "работаем над lazy import'ами в CPython и плачем под аниме" (на превью - я на стриме) Мы с @nkhitrov_blog, @fastnewsdev и Денисом Аникиным (в 2026 и без тг канала!) решили замутить стрим по питону и ... новый канал на ютюбе под названием "Вялые…
Значимые и незначимые пробелы в Python
Во время стрима я решил, что сейчас у меня будет приключение на 15 минут, что я быстренько запилю новую синтаксическую ошибку.
В чем суть?
Довольно легко опечататься и написать вместо корректного
И первая часть задачи у меня получилась прямо на стриме. Теперь
А вот часть с
А есть незначимые:
И как вы уже могли догадаться:
Более того, он абсолютно корректно работает. И жадно импортирует имя
Что собственно и стало причиной, почему в PEP сделали
Теперь я поправил свой PR, чтобы выкидывать еще один
Кстати, тут можно сравнить мой код со слопусом. К вопросу о "качестве" ИИ-поделок.
Теперь оба случая ошибочного импорта обрабатываются корректно.
Про канал / стримы
После стрима случилось главное: мы почти 3 часа обсуждали, что хотим делать и какую ценность нести людям.
Мы поняли, что главная ценность, которую мы можем и хотим давать: помогать людям бороться со страхами. На каждом углу нас пытаются запсиопить тейками вроде "ИИ заменило всех программистов", "IT В С Е", "всех сократили", "работы нет" и прочее.
Кажется, что с таким нужно бороться рациональностью, взвешенной позицией, фактами и техническими контентом. То, что мы делаем и любим. Не хочется хайпить на страхах людей, хочется помогать людям быть счастливыми и уверенными. По мере сил, конечно.
Обсуждение: а какой контент хотелось бы увидеть вам? :)
| Поддержать | YouTube | GitHub | Чат |
Во время стрима я решил, что сейчас у меня будет приключение на 15 минут, что я быстренько запилю новую синтаксическую ошибку.
В чем суть?
Довольно легко опечататься и написать вместо корректного
lazy from os import path неправильную форму from os lazy import path. На что человек просто получит голый SyntaxError без подсказок и советов. Оно работает, но DX не самый лучший для новой фичи. Особенно, учитывая тот факт, что from os lazy import path выглядит консистентно с lazy import os.И первая часть задачи у меня получилась прямо на стриме. Теперь
from os lazy import path выдает красивую ошибку:
>>> from os lazy import path
File "<python-input-0>", line 1
from os lazy import path
^^^^
SyntaxError: use 'lazy from ... ' instead of 'from ... lazy import'
А вот часть с
from . lazy import name у меня сразу не вышла. На стриме оч сложно программировать. Я, честно сказать, сначала растерялся. А потом понял: в питоне есть значимые пробелы: например для идентации кода. Они превращаются в токен INDENT. А есть незначимые:
a+b и a + b - одинаковый код. Что на самом деле ведет к чудовищам вида:
>>> 1. .real
1.0
>>> 1if True else 0
<python-input-2>:1: SyntaxWarning: invalid decimal literal
1
>>> [1.0for _ in range(1)]
<python-input-3>:1: SyntaxWarning: invalid decimal literal
[1.0]
И как вы уже могли догадаться:
from . lazy import x и from .lazy import x - ОДИН И ТОТ ЖЕ КОД.Более того, он абсолютно корректно работает. И жадно импортирует имя
x из модуля lazy.Что собственно и стало причиной, почему в PEP сделали
lazy from, а не from ... lazy import.Теперь я поправил свой PR, чтобы выкидывать еще один
SyntaxWarning:
>>> from . lazy import x
<python-input-0>:1: SyntaxWarning: 'from . lazy import' is the same as 'from .lazy import'; did you mean 'lazy from . import'?
Кстати, тут можно сравнить мой код со слопусом. К вопросу о "качестве" ИИ-поделок.
Теперь оба случая ошибочного импорта обрабатываются корректно.
Про канал / стримы
После стрима случилось главное: мы почти 3 часа обсуждали, что хотим делать и какую ценность нести людям.
Мы поняли, что главная ценность, которую мы можем и хотим давать: помогать людям бороться со страхами. На каждом углу нас пытаются запсиопить тейками вроде "ИИ заменило всех программистов", "IT В С Е", "всех сократили", "работы нет" и прочее.
Кажется, что с таким нужно бороться рациональностью, взвешенной позицией, фактами и техническими контентом. То, что мы делаем и любим. Не хочется хайпить на страхах людей, хочется помогать людям быть счастливыми и уверенными. По мере сил, конечно.
Обсуждение: а какой контент хотелось бы увидеть вам? :)
| Поддержать | YouTube | GitHub | Чат |
GitHub
Improve lazy imports syntax errors · Issue #150459 · python/cpython
Feature or enhancement Currently there are several cases that can be improved when there are syntax errors in the code. The most important one in my opinion is from os lazy import path. This is the...
5🔥71❤44👍13💩1
Зеркало PyPI
На нескольких проектах последние несколько дней сталкиваемся с проблемами с доступом к PyPI: как локально, так и в CI. Печально.
Если у вас есть такая же проблема, можете воспользоваться PyPI зеркалом от GitVerse: https://gitverse.ru/docs/artifactory/registry-mirrors/pypi-mirror?utm_source=tg&utm_medium=fix&utm_campaign=bloggers&utm_content=post&utm_term=nikitasobolev&utm_erid=2VfnxxwjcVp
Все пакеты и все версии, которые есть на PyPI - оттуда тоже доступны. Перевел консалтинговые проекты - заработало.
Как настроить?
pip, документация:
Можно настроить как альтернативный, а не главный индекс: вместо global.index-url используйте global.extra-index-url.
poetry, документация:
Сначала пробуем pypi, если не вышло - идем в зеркало.
Можно повернуть priority в зависимости от ваших задач.
uv, документация:
Здесь аналогично, default имеет самый низкий приоритет.
Важно: обратите внимание, чтобы при использовании любых зеркал, у вас были корректные хеши пакетов при установке. poetry и uv делают такое по-умолчанию. А вот pip требует явного --require-hashes параметра. Сам pip тем временем не умеет дампить хеши, но pip-tools умеет 🌚
Пример, корректной работы:
Еще есть зеркала для:
- DockerHub
- NPM
- Maven
Обсуждение: вас затронула проблема?
Реклама. ПАО "СБЕРБАНК", ИНН 7707083893. erid: 2VfnxxwjcVp
На нескольких проектах последние несколько дней сталкиваемся с проблемами с доступом к PyPI: как локально, так и в CI. Печально.
All attempts to connect to pypi.org failed.
Probable Causes:
- the server is not responding to requests at the moment
- the hostname cannot be resolved by your DNS
- your network is not connected to the internet
Если у вас есть такая же проблема, можете воспользоваться PyPI зеркалом от GitVerse: https://gitverse.ru/docs/artifactory/registry-mirrors/pypi-mirror?utm_source=tg&utm_medium=fix&utm_campaign=bloggers&utm_content=post&utm_term=nikitasobolev&utm_erid=2VfnxxwjcVp
Все пакеты и все версии, которые есть на PyPI - оттуда тоже доступны. Перевел консалтинговые проекты - заработало.
Как настроить?
pip, документация:
# Установка одного пакета:
pip install attrs --extra-index-url https://pypi-mirror.gitverse.ru/simple/
# Настройка для всех команд:
pip config --user set global.index-url https://pypi-mirror.gitverse.ru/simple/
pip config --user set global.trusted-host pypi-mirror.gitverse.ru
Можно настроить как альтернативный, а не главный индекс: вместо global.index-url используйте global.extra-index-url.
poetry, документация:
# pyproject.toml
[[tool.poetry.source]]
name = "pypi"
priority = "primary"
[[tool.poetry.source]]
name = "gitverse"
url = "https://pypi-mirror.gitverse.ru/simple/"
priority = "supplemental"
Сначала пробуем pypi, если не вышло - идем в зеркало.
Можно повернуть priority в зависимости от ваших задач.
uv, документация:
# pyproject.toml
[[tool.uv.index]]
url = "https://pypi.org/simple/"
name = "pypi"
default = true
[[tool.uv.index]]
url = "https://pypi-mirror.gitverse.ru/simple/"
name = "gitverse"
Здесь аналогично, default имеет самый низкий приоритет.
Важно: обратите внимание, чтобы при использовании любых зеркал, у вас были корректные хеши пакетов при установке. poetry и uv делают такое по-умолчанию. А вот pip требует явного --require-hashes параметра. Сам pip тем временем не умеет дампить хеши, но pip-tools умеет 🌚
Пример, корректной работы:
» uv sync --default-index https://pypi-mirror.gitverse.ru/simple/
Resolved 171 packages in 20ms
Checked 102 packages in 13ms
Еще есть зеркала для:
- DockerHub
- NPM
- Maven
Обсуждение: вас затронула проблема?
Реклама. ПАО "СБЕРБАНК", ИНН 7707083893. erid: 2VfnxxwjcVp
python-poetry.org
Repositories | Documentation | Poetry - Python dependency management and packaging made easy
Repositories
Poetry supports the use of PyPI and private repositories for discovery of
packages as well as for publishing your projects.
By default, Poetry is configured to use the PyPI repository,
for package installation and publishing.
So, when you add…
Poetry supports the use of PyPI and private repositories for discovery of
packages as well as for publishing your projects.
By default, Poetry is configured to use the PyPI repository,
for package installation and publishing.
So, when you add…
1👍79🤡66👎45❤21🤮18🔥16👏4😁4😢2🤯1
Почему msgspec такой быстрый?
Несколько дней назад я решил разобраться в устройстве
Как быстро распарсить json?
Традиционные парсеры json делают так:
- Парсим весь json документ
- Используем промежуточный слой для хранения json как примитивных Python объектов: dict, list, int, str, None, тд
- Превращаем Python объекты в финальный вариант: датаклассы, модели, более сложные типы, тд
Пример:
Все самое интересное происходит в JSONDecoder_decode и в json_decode:
1. Мы используем
2. Далее мы проваливаемся в функцию json_decode_nocustom, она очень красивая:
Буквально по первому символу, мы можем парсить нужные части. Хитрый json_decode_object посмотрит, что
То есть: ключ в C мы конечно обязаны прочитать в виде
Минусы
На данный момент у
Но, вопрос решаем. Сделаем.
Второй минус: мало всего можно выразить.
Что будет с msgspec дальше?
Новые релизы добавят кучу новых фичей. Поддержку
А еще я параллельно добавил поддержку
Обсуждение: а вы пробовали msgspec? Какие впечатления?
| Поддержать | YouTube | GitHub | Чат |
Несколько дней назад я решил разобраться в устройстве
msgspec. Получилось како бычно: я напал на него со своими PRами, мне через день выдали права на merge и release. Но самое главное: теперь я могу рассказать вам про внутреннее устройство самого быстрого сериализатора для json в питоне.Как быстро распарсить json?
Традиционные парсеры json делают так:
- Парсим весь json документ
- Используем промежуточный слой для хранения json как примитивных Python объектов: dict, list, int, str, None, тд
- Превращаем Python объекты в финальный вариант: датаклассы, модели, более сложные типы, тд
msgspec использует несколько важных хитростей, чтобы парсить json наиболее быстрым способом.Пример:
>>> import msgspec
>>> class User(msgspec.Struct):
... username: str
... email: str
...
>>> decoder = msgspec.json.Decoder(User)
>>> decoder.decode(b'{"username": "example", "email": "email@example.com"}')
User(username='example', email='email@example.com')
Все самое интересное происходит в JSONDecoder_decode и в json_decode:
1. Мы используем
TypeNode *type для мета информации о том, что мы будем парсить. В нашем случае там будет struct User с двумя str полями2. Далее мы проваливаемся в функцию json_decode_nocustom, она очень красивая:
static MS_INLINE PyObject *
json_decode_nocustom(
JSONDecoderState *self, TypeNode *type, PathNode *path
) {
// ...
switch (c) {
case 'n': return json_decode_none(self, type, path);
case 't': return json_decode_true(self, type, path);
case 'f': return json_decode_false(self, type, path);
case '[': return json_decode_array(self, type, path);
case '{': return json_decode_object(self, type, path);
case '"': return json_decode_string(self, type, path);
default: return json_maybe_decode_number(self, type, path);
}
}
Буквально по первому символу, мы можем парсить нужные части. Хитрый json_decode_object посмотрит, что
type у нас MS_TYPE_STRUCT и будет парсить сразу msgspec.Struct. Что еще более хитро, то парситься будут только те ключи, которые явно указаны в User, остальные будут просто пропускаться через вызов json_skip.То есть: ключ в C мы конечно обязаны прочитать в виде
char *, чтобы сравнить его с существующими ключами User. Но вот создавать дорогие промежуточные Python объекты мы не будем. Если ключ нам не нужен, то и значение его мы парсить не будем. На выходе получим сразу объект User без промежуточных слоев и их аллокаций. Быстро? Быстро.Минусы
На данный момент у
msgspec есть главный минус: плохая поддержка Union типов. То есть: некоторые комбинации данных вообще не получится распарсить. Например: str | bytes. Или два датакласса. Или два тайпдикта. Почему? Потому что оптимизации пока мешают работе 🌚Но, вопрос решаем. Сделаем.
Второй минус: мало всего можно выразить.
pydantic умеет куда больше. Потому я в django-modern-rest и сделал выбор сериализатора для каждого отдельного контроллера. Чтобы точечно выбирать скорость vs функциональность.Что будет с msgspec дальше?
Новые релизы добавят кучу новых фичей. Поддержку
pyrefly, heap types, поддержку subinterpreters, FT, более гибкие правила проверок значений и тд.А еще я параллельно добавил поддержку
frozendict для Python 3.15+ и предложил сделать новое АПИ для него: PyFrozenDict_FromDictSteal, потому что текущее АПИ работает за O(n * 2), когда можно за O(n).Обсуждение: а вы пробовали msgspec? Какие впечатления?
| Поддержать | YouTube | GitHub | Чат |
GitHub
Pull requests · msgspec/msgspec
A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML - Pull requests · msgspec/msgspec
2❤81👍58🔥17😱1🤡1
Генерируем Rust код из Python и становимся крабами
Проект "острый краб": https://github.com/kushaldas/spicycrab
Вы же знаете, что вы узнаете про все важные штуки в питоне первыми? На ближайшем Language Summit в июле Кушал Дас - core-разработчик CPython - представит свой новый проект. Но зачем ждать июля, когда код открыт? Давайте смотреть и пробовать!
В чем главная идея?
- Пишем на типизированном Python
- Получаем на выходе Rust код, который работает в десятки или сотни раз быстрее
- Можем использовать в Python крейты Rust и Python пакеты, что? 🙀
(проект еще не просто в альфе, а в пре-альфе, но мы тут просто любим странное, ставь 🕊, если просто заходишь сюда почитать про непонятное и удивительное)
Начнем с простого:
Запустим:
Прикол! Давайте сделаем сложнее. Возьмем clap (популярная библиотека для парсинга CLI параметров в расте) и сделаем мини CLI с ее помощью ... на питоне.
1. Скачиваем Rust зависимость и генерим из нее Python стабы:
2. Смотрим, что там внутри правда Python стабы, удивляемся
3. Устанавливаем стабы:
4. Пишем на питоне:
5. Транспилим:
6. Получаем
7. Запускаем:
Теперь у вас нет уважительных причин, чтобы говорить "я не знаю раст" 🌚️️
Зачем?
А если серьезно, то не совсем пока понятно - какую нишу будет занимать данный проект.
Сам автор говорит:
> Write typed Python and generate working Rust code via spicycrab. This currently includes part of stdlib, async (via tokio), actix-web examples. Slowly more and more Rust crates are available as stub typed Python modules, which we can use like normal Python code while developing and then compiling the generated Rust code as final output. The final goal is to be able to write smaller production code using spicycrab.
Кажется, что ниша довольно маленькая. Если вам реально хочется писать Python + Rust код вместе (что вообще-то лютейшая база, например
- https://github.com/pyo3/pyo3 - для использования Rust вместе с CPython биндингами
- https://github.com/pyo3/maturin - система сборки для такие проектов
Есть проекты чуть менее универсальные, например:
- https://github.com/RustPython/RustPython - интерпретатор Python на Rust, там тоже можно писать модули на расте для питона своим особым способом
- https://github.com/youknowone/pyre - новый интерпретатор Python на Rust (от того же автора) но с Free-Threading и JIT из PyPy, в некоторых случаях в 45 раз быстрее CPython, goes brrrr
- Поддержка Rust напрямую в CPython: https://xn--r1a.website/opensource_findings/941 Ждете? :)
И еще куча всего другого.
Но, будет интересно посмотреть, что выйдет из такого довольно необычного опыта.
Обсуждение: Знаете ли вы раст? Хотите ли изучить? Видите ли применения у себя на работе?
| Поддержать | YouTube | GitHub | Чат |
Проект "острый краб": https://github.com/kushaldas/spicycrab
Вы же знаете, что вы узнаете про все важные штуки в питоне первыми? На ближайшем Language Summit в июле Кушал Дас - core-разработчик CPython - представит свой новый проект. Но зачем ждать июля, когда код открыт? Давайте смотреть и пробовать!
В чем главная идея?
- Пишем на типизированном Python
- Получаем на выходе Rust код, который работает в десятки или сотни раз быстрее
- Можем использовать в Python крейты Rust и Python пакеты, что? 🙀
(проект еще не просто в альфе, а в пре-альфе, но мы тут просто любим странное, ставь 🕊, если просто заходишь сюда почитать про непонятное и удивительное)
Начнем с простого:
print('Hello world') Запустим:
crabpy transpile ex.py и получим:
fn main() {
println!("Hello world");
}
Прикол! Давайте сделаем сложнее. Возьмем clap (популярная библиотека для парсинга CLI параметров в расте) и сделаем мини CLI с ее помощью ... на питоне.
1. Скачиваем Rust зависимость и генерим из нее Python стабы:
cookcrab generate clap -o rust-stubs/2. Смотрим, что там внутри правда Python стабы, удивляемся
3. Устанавливаем стабы:
pip install -e ./rust-stubs/clap_builder ./rust-stubs/clap4. Пишем на питоне:
from spicycrab_clap import Command, Arg, ArgMatches
def main() -> None:
matches: ArgMatches = (
Command.new("myapp")
.arg(Arg.new("name").required(True))
.get_matches()
)
name: str = matches.get_one("name").unwrap().clone()
print(f"Hello, {name}!")
5. Транспилим:
crabpy transpile ex.py6. Получаем
pub fn main() {
let matches: clap_builder::ArgMatches = clap::Command::new("myapp")
.arg(clap::Arg::new("name").required(true))
.get_matches();
let name: String = matches.get_one::<String>("name").cloned().unwrap().to_string();
println!("{}", format!("Hello, {}!", name));
}
7. Запускаем:
» cargo run -- Nikita
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `/Users/sobolev/Desktop/spicycrab/rusty/target/debug/ex Nikita`
Hello, Nikita!
Теперь у вас нет уважительных причин, чтобы говорить "я не знаю раст" 🌚️️
Зачем?
А если серьезно, то не совсем пока понятно - какую нишу будет занимать данный проект.
Сам автор говорит:
> Write typed Python and generate working Rust code via spicycrab. This currently includes part of stdlib, async (via tokio), actix-web examples. Slowly more and more Rust crates are available as stub typed Python modules, which we can use like normal Python code while developing and then compiling the generated Rust code as final output. The final goal is to be able to write smaller production code using spicycrab.
Кажется, что ниша довольно маленькая. Если вам реально хочется писать Python + Rust код вместе (что вообще-то лютейшая база, например
ruff и uv ровно так и написаны), то есть уже готовые проекты:- https://github.com/pyo3/pyo3 - для использования Rust вместе с CPython биндингами
- https://github.com/pyo3/maturin - система сборки для такие проектов
Есть проекты чуть менее универсальные, например:
- https://github.com/RustPython/RustPython - интерпретатор Python на Rust, там тоже можно писать модули на расте для питона своим особым способом
use rustpython::vm::pymodule;
#[pymodule]
mod test_module {
#[pyfunction]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
}
- https://github.com/youknowone/pyre - новый интерпретатор Python на Rust (от того же автора) но с Free-Threading и JIT из PyPy, в некоторых случаях в 45 раз быстрее CPython, goes brrrr
- Поддержка Rust напрямую в CPython: https://xn--r1a.website/opensource_findings/941 Ждете? :)
И еще куча всего другого.
Но, будет интересно посмотреть, что выйдет из такого довольно необычного опыта.
Обсуждение: Знаете ли вы раст? Хотите ли изучить? Видите ли применения у себя на работе?
| Поддержать | YouTube | GitHub | Чат |
GitHub
GitHub - kushaldas/spicycrab
Contribute to kushaldas/spicycrab development by creating an account on GitHub.
1🕊161🔥31🤯12👍8🤔4❤3😁3💩2🎉1
Если вы понимаете данный баг, то вы знаете питон лучше 95% людей
А если нет, то вы многое узнаете про то, как работает память и почему мутабельностью стоит пользоваться с осторожностью.
Недавно я увидел один из лучших багов в CPython за долгое время. А я видел много багов 🌚️️
Вот код, который делает две критичные безумные вещи (попробуйте их найти прежде, чем читать дальше):
Разбор бага
Во-первых, что произойдет?
1. Мы мутируем встроенный и иммутабельный тип
2. Интерпретатор закрашится; не упадет с исключением, а словит core dump на уровне C кода
Но почему? Пройдемся по каждой строке. Со ссылками на исходники: кликайте и читайте!
1. Сначала мы создадим класс
2. Далее, мы сравниваем
3. vars возвращает вам
4. Как работает сравнение для
5. В случае с
6. При сравнении
7. Теперь у нас есть
8. Далее происходит еще более дикое. Мы удаляем метод, который добавили через
9. Питон не ожидает такого: методы у встроенных типов не могут появляться и исчезать. И при следующем обращении к
пу-пу-пу
Фикс
Баг: https://github.com/python/cpython/issues/152405
Как такое чинить?
1. Нужно сохранить обратную совместимость для всех видов сравнений. Менять типы или значения нельзя
2. Необходимо убрать креш и мутацию типа
3. Сильно раздувать потребление памяти / время работы тоже нельзя
Мой PR: https://github.com/python/cpython/pull/152483
Что он делает? Если мы сравниваем прокси поверх обычного словаря, но не с известными нам безопасными типами, то мы делаем копию словаря и сравниваем ее:
Таким образом - все ошибки выше уходят. Любая мутация останется в копии. Доп память не тратится в большом количестве популярных случаев.
Данный баг все еще есть на всех версиях питона. Я вам его не показывал, вы ничего не видели.
Обсуждение: какие у вас были самые кринжовые / прикольные баги?
| Поддержать | YouTube | GitHub | Чат |
А если нет, то вы многое узнаете про то, как работает память и почему мутабельностью стоит пользоваться с осторожностью.
Недавно я увидел один из лучших багов в CPython за долгое время. А я видел много багов 🌚️️
Вот код, который делает две критичные безумные вещи (попробуйте их найти прежде, чем читать дальше):
class Evil:
def __eq__(self, other):
return other
leaked = vars(list) == Evil()
name = "example"
leaked[name] = lambda self: "probe"
print(getattr(list, name)([]))
del leaked[name]
print(hasattr(list, name))
Разбор бага
Во-первых, что произойдет?
1. Мы мутируем встроенный и иммутабельный тип
list, хотя такое должно быть невозможно2. Интерпретатор закрашится; не упадет с исключением, а словит core dump на уровне C кода
Но почему? Пройдемся по каждой строке. Со ссылками на исходники: кликайте и читайте!
1. Сначала мы создадим класс
Evil, который просто возвращает из __eq__ второй объект, который ему передали. Так можно делать, тут нет ничего сломанного.2. Далее, мы сравниваем
vars(list) с Evil, и вот тут как раз в leaked попадет второй объект из Evil.__eq__, в нашем случае vars(list)3. vars возвращает вам
list.__dict__, который является не обычным dict, а types.MappingProxyType, то есть иммутабельным маппингом поверх оригинального значения. Добавлять в него ключи нельзя. Потому что мы не хотим, чтобы в список или другие типы нам подкидывали какие-то новые методы во время работы программы4. Как работает сравнение для
mappingproxy? mappingproxy хранит в себе оригинальный мутабельный словарь, который он "проксирует" или "защищает от изменений". И сравнивает на самом деле не себя, а оригинальный объект5. В случае с
list.__dict__ мы получаем PyDictProxy_New(self->tp_dict), где хранится тот самый настоящий и защищенный __dict__ из типа list, который обычно не доступен вне C кода6. При сравнении
mappingproxy разворачивается и достает из себя ->mapping, тот самый чистый и мутабельный ->tp_dict7. Теперь у нас есть
->tp_dict, мы можем в него добавлять методы: leaked[name] = lambda self: "probe". Они будут работать. Мы только что достигли пункта 1. и мутировали встроенный Python тип без единого импорта8. Далее происходит еще более дикое. Мы удаляем метод, который добавили через
del leaked[name]9. Питон не ожидает такого: методы у встроенных типов не могут появляться и исчезать. И при следующем обращении к
hasattr(list, name) крашится вот тут на обращении к уже освобожденной памяти. EXC_BAD_ACCESS, пункт 2. палпу-пу-пу
Фикс
Баг: https://github.com/python/cpython/issues/152405
Как такое чинить?
1. Нужно сохранить обратную совместимость для всех видов сравнений. Менять типы или значения нельзя
2. Необходимо убрать креш и мутацию типа
3. Сильно раздувать потребление памяти / время работы тоже нельзя
Мой PR: https://github.com/python/cpython/pull/152483
Что он делает? Если мы сравниваем прокси поверх обычного словаря, но не с известными нам безопасными типами, то мы делаем копию словаря и сравниваем ее:
if (
PyDict_CheckExact(v->mapping) &&
!(PyAnyDict_CheckExact(w) || PyODict_CheckExact(w))
) {
// So, instead we send a copy:
PyObject *copy = PyDict_Copy(v->mapping);
if (copy == NULL) {
return NULL;
}
PyObject *res = PyObject_RichCompare(copy, w, op);
Py_DECREF(copy);
return res;
}
Таким образом - все ошибки выше уходят. Любая мутация останется в копии. Доп память не тратится в большом количестве популярных случаев.
Данный баг все еще есть на всех версиях питона. Я вам его не показывал, вы ничего не видели.
Обсуждение: какие у вас были самые кринжовые / прикольные баги?
| Поддержать | YouTube | GitHub | Чат |
GitHub
cpython/Python/bltinmodule.c at f6e904e1a666cb1e5664750b1c3d8f89cba3a769 · python/cpython
The Python programming language. Contribute to python/cpython development by creating an account on GitHub.
👍47🔥36🤯12❤7👎1
Пользуясь случаем: у нас 10 июля митап в Нижнем Новгороде.
https://pytho-nn.timepad.ru/event/4050146/
В программе 4 крутейших юбилейных доклада от гостей города и (даже!) нижегородца:
- Артем Пашков, Нижний Новгород, Сообщество "Опенсорсеры", Как сообщество Опенсорсеры помогает open source проектам и разработчикам?
Отвечу на главный вопрос: нужно ли лично вам занимать опенсорсом? И как начать?
Расскажу про проблемы, знакомые многим: недостаток внимания к своему проекту, где искать контрибьюторов, куда самому законтрибьютить, а также как получить полезный фидбек.
- Илья Солин, Уфа, ТБанк, https://xn--r1a.website/http_418_i_am_a_teapot, Алгебраические эффекты: понять, полюбить и никогда не тащить в прод
Разберём концепцию теоретически (почему это классно), попробуем реализовать её на Python и поймём, стоило ли оно того.
- Георгий Бородин, Москва, Как я перестал бояться и полюбил бойлерплейт
Благие намерения далеко не всегда приводят к хорошему, но если не опускать лапки – наверняка получится сделать систему мечты. Цена этого – вопрос, о котором и хочется рассказать (собираюсь рассказать об одном очень грязном способе якобы оптимизации деливери, который заставил меня ползать по флеймграфам и проклинать себя же и об одном, который позволил мне перестать ждать фронтовых задач).
- Евгений Блинов, The Mutating Company, Из чего состоит фреймворк мутационного тестирования?
В процессе создания своего фреймворка МТ мне потребовалось создать некоторое количество промежуточных библиотек. Подробнее о них расскажу в докладе.
Спикеров можно и нужно мучать вопросами.
Ну а после: афте-пати в баре до закрытия, афте-афте-пати до самого утра.
Ждем всех 10 июля по адресу Алексеевская, 6/16, ИТ Лекторий «Горький Тех»
Сбор гостей с 18:00, стартуем в 18:30
Приходите, приезжайте :)
https://pytho-nn.timepad.ru/event/4050146/
В программе 4 крутейших юбилейных доклада от гостей города и (даже!) нижегородца:
- Артем Пашков, Нижний Новгород, Сообщество "Опенсорсеры", Как сообщество Опенсорсеры помогает open source проектам и разработчикам?
Отвечу на главный вопрос: нужно ли лично вам занимать опенсорсом? И как начать?
Расскажу про проблемы, знакомые многим: недостаток внимания к своему проекту, где искать контрибьюторов, куда самому законтрибьютить, а также как получить полезный фидбек.
- Илья Солин, Уфа, ТБанк, https://xn--r1a.website/http_418_i_am_a_teapot, Алгебраические эффекты: понять, полюбить и никогда не тащить в прод
Разберём концепцию теоретически (почему это классно), попробуем реализовать её на Python и поймём, стоило ли оно того.
- Георгий Бородин, Москва, Как я перестал бояться и полюбил бойлерплейт
Благие намерения далеко не всегда приводят к хорошему, но если не опускать лапки – наверняка получится сделать систему мечты. Цена этого – вопрос, о котором и хочется рассказать (собираюсь рассказать об одном очень грязном способе якобы оптимизации деливери, который заставил меня ползать по флеймграфам и проклинать себя же и об одном, который позволил мне перестать ждать фронтовых задач).
- Евгений Блинов, The Mutating Company, Из чего состоит фреймворк мутационного тестирования?
В процессе создания своего фреймворка МТ мне потребовалось создать некоторое количество промежуточных библиотек. Подробнее о них расскажу в докладе.
Спикеров можно и нужно мучать вопросами.
Ну а после: афте-пати в баре до закрытия, афте-афте-пати до самого утра.
Ждем всех 10 июля по адресу Алексеевская, 6/16, ИТ Лекторий «Горький Тех»
Сбор гостей с 18:00, стартуем в 18:30
Приходите, приезжайте :)
pytho-nn.timepad.ru
PythoNN 10: митап питонистов в Нижнем Новгороде, июль 2026 / События на TimePad.ru
🔥25👍7❤4