Находки в опенсорсе pinned «Записи с нашей бесплатной конфы в Нижнем подъехали! Во-первых, хочу еще раз повторить слова благодарности всем: организаторам и волонтерам, спикерам, участникам. Отдельно хочу отметить тех, кто поддержал конфу анонсами. Приехало и пришло очень много людей:…»
Минусы Litestar
Внезапно вспомнил, что я меинтейнер фреймворка Litestar.
Для тех, кто пропустил:
> Litestar не является микро-фреймворком. В отличие от таких фреймворков, как FastAPI, Starlette или Flask,
> Litestar изначально включает множество функций, необходимых для типичного современного веб-приложения,
> таких как интеграция с ORM, клиентские и серверные сессии, кэширование, поддержка OpenTelemetry и многое другое.
И он классный:
- Быстрый
- Работает с
- Предоставляет базовые примитивы для работы с логикой: DTOs, Repository, Service (часть из них в
- Умеет из коробки в аутентификацию, метрики, DI, CORS, CSRF, кеширование, логирование, мониторинг, вебсокеты, htmx, сессии, загрузку файлов, разные ORMки и много всего еще
- Можно делать не только API, но и нормальные шаблончики
- Он с нами уже несколько лет, он работает
- А еще его делает большая команда, а не один человек
Кароче, просто лучший фреймворк (кроме Django, конечно).
Но! Сегодня речь пройдет про минусы. Которые скоро пофиксят в
Минусы
1. Самое главное: DI на именах. Да. Вот так:
Что очень плохо. Тип
Планы? Я предложил использовать dishka в качестве дефолтного DI, а старый задеприкейтить.
Высказать свое обоснованное мнение можно тут (или просто лайкнуть пост): https://github.com/orgs/litestar-org/discussions/4377
Хочу верить, что мы сможем поправить данную проблему в
2. DI в middleware. А точнее отсутствие DI в middleware. Пока что приходится прокидывать зависимости через
3. Своя схема для OpenAPI. Litestar переписал дефолтную схему pydantic, что позволило использовать более строгую схему, но переодически новые типы отваливаются. Например,
4.
5. CLI местами разваливается, очень много багов и плохая читаемость
6. Очень сырая документация. Очень плохая навигация и структура, очень мало примеров, мало людей ее читало, мало людей находило проблемы, мало людей присылало PRы. Тут нужна ваша помощь очень сильно!
Итог
Отличный фреймворк, у которого есть некоторое количество детских проблем и ошибок проектирования. Но что отличает? Про них говорят, их исправляют.
Полный роадмап для версии
Обсуждение: Как вам Litestar? Какие минусы я забыл? Каких фичей не хватает? Что показалось сложным? Буду рад обратной связи :)
Внезапно вспомнил, что я меинтейнер фреймворка Litestar.
Для тех, кто пропустил:
> Litestar не является микро-фреймворком. В отличие от таких фреймворков, как FastAPI, Starlette или Flask,
> Litestar изначально включает множество функций, необходимых для типичного современного веб-приложения,
> таких как интеграция с ORM, клиентские и серверные сессии, кэширование, поддержка OpenTelemetry и многое другое.
from dataclasses import dataclass
from litestar import Litestar, post
@dataclass
class User:
name: str
@post(path="/")
async def index(data: User) -> User:
return data
app = Litestar(route_handlers=[index])
И он классный:
- Быстрый
- Работает с
Pydantic, msgspec и даже базовые dataclasses в качестве моделей- Предоставляет базовые примитивы для работы с логикой: DTOs, Repository, Service (часть из них в
advanced_sqlalchemy, очень удобно для крудов)- Умеет из коробки в аутентификацию, метрики, DI, CORS, CSRF, кеширование, логирование, мониторинг, вебсокеты, htmx, сессии, загрузку файлов, разные ORMки и много всего еще
- Можно делать не только API, но и нормальные шаблончики
- Он с нами уже несколько лет, он работает
- А еще его делает большая команда, а не один человек
Кароче, просто лучший фреймворк (кроме Django, конечно).
Но! Сегодня речь пройдет про минусы. Которые скоро пофиксят в
v3 (или которые все еще будут с нами)Минусы
1. Самое главное: DI на именах. Да. Вот так:
class UserController(Controller):
path = "/user"
dependencies = {"user": Provide(retrieve_db_user)}
@patch(path="/{user_id:uuid}") # <- тут тоже можно указывать `dependencies`
async def get_user(self, user: User) -> User: ...
Что очень плохо. Тип
user, который мы указываем в dependencies и в параметрах может не совпасть. Есть некоторая валидация для такого в рантайме, но все равно очень рисково. Планы? Я предложил использовать dishka в качестве дефолтного DI, а старый задеприкейтить.
Высказать свое обоснованное мнение можно тут (или просто лайкнуть пост): https://github.com/orgs/litestar-org/discussions/4377
Хочу верить, что мы сможем поправить данную проблему в
v3, ваши голоса – могут помочь :) 2. DI в middleware. А точнее отсутствие DI в middleware. Пока что приходится прокидывать зависимости через
app.state, что очень криво. Данная проблема признана ошибкой дизайна и будет исправлено в v3, ура!3. Своя схема для OpenAPI. Litestar переписал дефолтную схему pydantic, что позволило использовать более строгую схему, но переодически новые типы отваливаются. Например,
pydantic.Json не обработан, имеет кривую схему. Сейчас мы обсуждаем стоит ли откатиться до дефолтной схемы. Стоит ли?4.
PydanticPlugin игнорирует ConfigDict, который объявлен в самой моделе, в v3 будет пофикшено. Сейчас параметры вроде by_alias и round_trip надо передавать в плагин. Что свело меня с ума, искал ошибку несколько часов5. CLI местами разваливается, очень много багов и плохая читаемость
6. Очень сырая документация. Очень плохая навигация и структура, очень мало примеров, мало людей ее читало, мало людей находило проблемы, мало людей присылало PRы. Тут нужна ваша помощь очень сильно!
Итог
Отличный фреймворк, у которого есть некоторое количество детских проблем и ошибок проектирования. Но что отличает? Про них говорят, их исправляют.
Полный роадмап для версии
v3: https://github.com/litestar-org/litestar/issues/4009Обсуждение: Как вам Litestar? Какие минусы я забыл? Каких фичей не хватает? Что показалось сложным? Буду рад обратной связи :)
GitHub
litestar-org/litestar
Light, flexible and extensible ASGI framework | Built to scale - litestar-org/litestar
11🔥105👍38❤24👎5🤯4👏1🤔1👌1
PEP 810: Explicit lazy imports
На обсуждение вышел новый PEP, который предлагает добавить в Python 3.15 новый вид импортов.
https://peps.python.org/pep-0810/
Как будет работать?
Импорты не будут подгружаться до момента первого обращения к объекту.
Зачем?
- Быстрее загружать модули
- Позволит убрать много импортов из функций / методов
- Позволит убрать
- Позволит решать циклические импорты
- Убирает необходимость в
Детали реализации
Планируется добавить:
- Функцию
- Специальный атрибут на уровне модуля
-
-
-
- Байткод
- Ошибки в именах модулей тоже будут ленивыми https://peps.python.org/pep-0810/#reification
Из забавного:
Реализация: https://github.com/LazyImportsCabal/cpython/tree/lazy
Обсуждение: как вам?
Бонус: меня тут в комментах спрашивают, куда я пропал. Я пропал в опенсорсе, пилю
https://github.com/wemake-services/django-modern-rest
| Поддержать | YouTube | GitHub | Чат |
На обсуждение вышел новый PEP, который предлагает добавить в Python 3.15 новый вид импортов.
https://peps.python.org/pep-0810/
lazy import json
lazy from json import dumps
Как будет работать?
Импорты не будут подгружаться до момента первого обращения к объекту.
import sys
lazy import json
print('json' in sys.modules) # Модуля еще нет
# Загрузка начинается вот тут:
result = json.dumps({"hello": "world"})
print('json' in sys.modules) # Теперь он загружен
Зачем?
- Быстрее загружать модули
- Позволит убрать много импортов из функций / методов
- Позволит убрать
if TYPE_CHECKING: import some_module, было множество предложений по добавлению import type конструкции, пример: https://discuss.python.org/t/type-only-imports/96755- Позволит решать циклические импорты
- Убирает необходимость в
LazyLoader и страшных вещей вроде https://scientific-python.org/specs/spec-0001Детали реализации
Планируется добавить:
- Функцию
__lazy_import__ (аналог __import__ для импорта )- Специальный атрибут на уровне модуля
__lazy_modules__, где будут храниться ленивые импорты текущего модуля-
types.LazyImportType как тип нового "ленивого" модуля (аналог `types.ModuleType`)-
sys.lazy_modules для списка ленивых модулей глобально-
sys.set_lazy_imports_filter для глобальных настроек импортов, что? 🤯- Байткод
IMPORT_NAME получит флаг, является ли импорт ленивым- Ошибки в именах модулей тоже будут ленивыми https://peps.python.org/pep-0810/#reification
Из забавного:
import * не будет доступен в lazy режиме.
# SyntaxError: lazy from ... import * is not allowed
lazy from json import *
Реализация: https://github.com/LazyImportsCabal/cpython/tree/lazy
Обсуждение: как вам?
Бонус: меня тут в комментах спрашивают, куда я пропал. Я пропал в опенсорсе, пилю
django-modern-rest. Простую и удобную библиотеку для REST API в Django. Пока на стадии pre-alpha, но уже скоро будет первый релиз. Можно уже ставить ⭐, чтобы потом всем говорить, что первыми узнали про новую модную штуку!https://github.com/wemake-services/django-modern-rest
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 810 – Explicit lazy imports | peps.python.org
This PEP introduces syntax for lazy imports as an explicit language feature:
60🔥168👍32👎20🤮8💩8🤔7🤯6❤5👏4😱2🎉1
Зачем нужен новый REST API для Django?
Последний месяц я крайне увлечен созданием https://github.com/wemake-services/django-modern-rest
(Кстати, у нас уже >200 звезд и 26 контрибьюторов при 0 релизов)
Ключевой вопрос – зачем? Что будет нового?
Во-первых, я крайне сильно люблю Django. Основная причина – под него есть буквально любые библиотеки. Все то, что в FastAPI нужно героически писать руками – в джанге уже давно есть и работает.
Но, есть несколько основных причин, почему люди думают, что не любят джангу:
1. DRF, тут без лишних слов – он ужасен. Нет типизации, нет async, очень сложно работать с ним в сложных случаях
2. Многие считают, что джанга - сложная. Однако, она как FastAPI или Litestar может спокойно уместиться в один файл: https://django-modern-rest.readthedocs.io/en/latest/pages/micro-framework.html
3. Есть критика за архитектуру: тут нечего особо даже комментировать. На любом фреймворке можно писать хорошо, на любом можно писать плохо. Слой фреймворка очень тонкий
4. Медленный. А вот тут остановимся подробнее.
На скринах выше можно сравнить, что с
Во-вторых, Django на длительный срок был в плену DRF. Который морально устарел еще в середине десятых.
Потом появилась
Вот такие проблемы мы решаем.
Одной строкой:
- Супер строгая OpenAPI схема и валидация при разработке, что мы ее соблюдаем
- Полная типизация всего
- Нормальный способ создания АПИ, без god-functions a-la FastAPI
-
- Быстро:
- Пидантик,
- Полная поддержка всего существующего в Django. От декораторов до миддлварь (с полной валидацией и OpenAPI схемой!)
- OpenAPI схема из коробки
- Удобное тестирование с polyfactory
- property-based тесты вашего АПИ одной командой благодаря schemathesis
Что еще будет:
- RSGI (да, на #rust скорее всего) под granian, в теории можем побить FastAPI после такого
- SSE с автоматической OpenAPI спекой и умной валидацией схемы
- JWT или любая другая аутентификация
- Какие-то части (скорее всего валидацию) мы компильнем cython, чтобы было еще быстрее
Modern? Modern!
Осталось дождаться. Релиз скоро!
И еще скоро будут несколько новых видео.
Мы регулярно постим задачки в @opensource_findings_python, так что можно нам помочь.
А если кто хочет мне закинуть на развитие опенсорса (за написание 32500 строк кода за 2 недели), то мой бусти открыт: https://boosty.to/sobolevn
Ну и звезды можно ставить, конечно же. Там посмотрите, какие люди нас уже советуют.
Большое спасибо Александру, Алексею, Роману, Максиму и всем остальным за неоценимую помощь. Пацаны, без вас никак! Лучшее сообщество!
Обсуждение: а чего бы вам хотелось в modern rest фреймворке? Чего сильно не хватает сейчас?
Последний месяц я крайне увлечен созданием https://github.com/wemake-services/django-modern-rest
(Кстати, у нас уже >200 звезд и 26 контрибьюторов при 0 релизов)
Ключевой вопрос – зачем? Что будет нового?
Во-первых, я крайне сильно люблю Django. Основная причина – под него есть буквально любые библиотеки. Все то, что в FastAPI нужно героически писать руками – в джанге уже давно есть и работает.
Но, есть несколько основных причин, почему люди думают, что не любят джангу:
1. DRF, тут без лишних слов – он ужасен. Нет типизации, нет async, очень сложно работать с ним в сложных случаях
2. Многие считают, что джанга - сложная. Однако, она как FastAPI или Litestar может спокойно уместиться в один файл: https://django-modern-rest.readthedocs.io/en/latest/pages/micro-framework.html
3. Есть критика за архитектуру: тут нечего особо даже комментировать. На любом фреймворке можно писать хорошо, на любом можно писать плохо. Слой фреймворка очень тонкий
4. Медленный. А вот тут остановимся подробнее.
На скринах выше можно сравнить, что с
django-modern-rest, без нескольких будущих оптимизаций (привет cython и rust!), голая джанга начинает выглядеть не так уж и медленнее FastAPI: бенчи.Во-вторых, Django на длительный срок был в плену DRF. Который морально устарел еще в середине десятых.
Потом появилась
django-ninja, которая хоть и намного лучше, но все равно не решает главную задачу: интеграция с существующими тулами. Конечно, если затащить FastAPI дизайн в чужой мир, то ничего не будет нормально работать 🌚️️Вот такие проблемы мы решаем.
Одной строкой:
- Супер строгая OpenAPI схема и валидация при разработке, что мы ее соблюдаем
- Полная типизация всего
- Нормальный способ создания АПИ, без god-functions a-la FastAPI
-
async без sync_to_async- Быстро:
msgspec для парсинга json (самый быстрый способ в питоне), практически 0 работы в рантайме (все делаем при импорте), оптимизации роутера (быстрее дефолтного в 51 раз)- Пидантик,
msgspec, или любой другой способ выражать модели. Хоть adaptix- Полная поддержка всего существующего в Django. От декораторов до миддлварь (с полной валидацией и OpenAPI схемой!)
- OpenAPI схема из коробки
- Удобное тестирование с polyfactory
- property-based тесты вашего АПИ одной командой благодаря schemathesis
Что еще будет:
- RSGI (да, на #rust скорее всего) под granian, в теории можем побить FastAPI после такого
- SSE с автоматической OpenAPI спекой и умной валидацией схемы
- JWT или любая другая аутентификация
- Какие-то части (скорее всего валидацию) мы компильнем cython, чтобы было еще быстрее
Modern? Modern!
Осталось дождаться. Релиз скоро!
И еще скоро будут несколько новых видео.
Мы регулярно постим задачки в @opensource_findings_python, так что можно нам помочь.
А если кто хочет мне закинуть на развитие опенсорса (за написание 32500 строк кода за 2 недели), то мой бусти открыт: https://boosty.to/sobolevn
Ну и звезды можно ставить, конечно же. Там посмотрите, какие люди нас уже советуют.
Большое спасибо Александру, Алексею, Роману, Максиму и всем остальным за неоценимую помощь. Пацаны, без вас никак! Лучшее сообщество!
Обсуждение: а чего бы вам хотелось в modern rest фреймворке? Чего сильно не хватает сейчас?
77👍189🔥75❤63💩6😁2
Находки в опенсорсе
minimal vscode: убираем вкладки https://www.youtube.com/watch?v=reT_wnDSaX4 Вкладки любят делать вид, что они очень полезны. Однако, такое впечатление обманчиво. Навигация по ним будет съедать у вас кучу времени. Взамен – есть способы лучше. Что будет в…
minimal vscode: убираем / кастомизируем status bar
https://www.youtube.com/watch?v=H5iVQZNk92s
В статусбаре в vscode – очень много всего: как полезного, так и лишнего.
Сегодня посмотрим, как можно его кастомизировать:
- Можно просто спрятать (как делаю я)
- Можно очень детально кастомизировать
- Можно перенести часть его функций в плагины
И вот тут главная фича vscode выходит наружу – у нас ведь просто браузер с html / css / js.
А значит, мы можем использовать css и js для кастомизации всего!
И оно будет работать одинаково даже в cloud версиях IDE.
В выпуске:
- Будем писать CSS для удаления лишнего из status bar
- И создавать локальные плагины на #javascript для кастомизации поведения редактора
Впереди еще пара взрывающих мозг видосов, будем и дальше превращать vscode в Черный Квадрат Малевича.
В следующих видео:
- Уберем оставшиеся части UI
- Сделаем свою тему, нативная интеграция самой минималистичной темной темы от меня (есть для vscode и nvim): https://github.com/pustota-theme/pustota
- Поговорим про git
- Научимся пользоваться дебагером, как будто мы трухацкеры
Обсуждение: То что vscode - браузер - плюс или минус лично для вас? И почему?
| Поддержать | YouTube | GitHub | Чат |
https://www.youtube.com/watch?v=H5iVQZNk92s
В статусбаре в vscode – очень много всего: как полезного, так и лишнего.
Сегодня посмотрим, как можно его кастомизировать:
- Можно просто спрятать (как делаю я)
- Можно очень детально кастомизировать
- Можно перенести часть его функций в плагины
И вот тут главная фича vscode выходит наружу – у нас ведь просто браузер с html / css / js.
А значит, мы можем использовать css и js для кастомизации всего!
И оно будет работать одинаково даже в cloud версиях IDE.
В выпуске:
- Будем писать CSS для удаления лишнего из status bar
"custom-ui-style.stylesheet": {
"#status\\.problems": {
"visibility": "hidden !important",
"display": "none !important",
}
}
- И создавать локальные плагины на #javascript для кастомизации поведения редактора
function updateColumnPosition() {
const positionLabel = document.querySelector(
'#status\\.editor\\.selection .statusbar-item-label',
)
if (!positionLabel || !positionLabel.textContent) {
// It might not exist for some reason ¯\_(ツ)_/¯
return
}
const currentLine = document.querySelector(
'.line-numbers.active-line-number',
)
// Now we would have the column position instead of the active line number:
const colNumber = positionLabel.textContent.match(/Col (\d+)/)
currentLine.textContent = colNumber[1]
}
Впереди еще пара взрывающих мозг видосов, будем и дальше превращать vscode в Черный Квадрат Малевича.
В следующих видео:
- Уберем оставшиеся части UI
- Сделаем свою тему, нативная интеграция самой минималистичной темной темы от меня (есть для vscode и nvim): https://github.com/pustota-theme/pustota
- Поговорим про git
- Научимся пользоваться дебагером, как будто мы трухацкеры
Обсуждение: То что vscode - браузер - плюс или минус лично для вас? И почему?
| Поддержать | YouTube | GitHub | Чат |
YouTube
Гайд по кастомизации vscode: чистим status bar, пишем плагины на #javascript
– Мой телеграм канал: https://xn--r1a.website/opensource_findings
– Поддержать: https://boosty.to/sobolevn
– Мой GitHub: https://github.com/sobolevn
– Прислать материал для видео: https://xn--r1a.website/opensource_findings_chat
Максимальная продуктивность и минимализм в visual…
– Поддержать: https://boosty.to/sobolevn
– Мой GitHub: https://github.com/sobolevn
– Прислать материал для видео: https://xn--r1a.website/opensource_findings_chat
Максимальная продуктивность и минимализм в visual…
3🔥68❤16👍15🤔2🤡1
Breaking news
В CPython предлагают добавить Rust: https://discuss.python.org/t/pre-pep-rust-for-cpython/104906
Пример кода: https://github.com/emmatyping/cpython/pull/13/files
Все подробности будут в @cpython_notes
Обсуждение: что думаете?
| Поддержать | YouTube | GitHub | Чат |
В CPython предлагают добавить Rust: https://discuss.python.org/t/pre-pep-rust-for-cpython/104906
Пример кода: https://github.com/emmatyping/cpython/pull/13/files
#[unsafe(no_mangle)]
pub unsafe extern "C" fn b64encode(
_module: *mut PyObject,
args: *mut *mut PyObject,
nargs: Py_ssize_t,
) -> *mut PyObject {
if nargs != 1 {
unsafe {
PyErr_SetString(
PyExc_TypeError,
c"b64encode() takes exactly one argument".as_ptr(),
);
}
return ptr::null_mut();
}
let source = unsafe { *args };
let buffer = match unsafe { BorrowedBuffer::from_object(source) } {
Ok(buf) => buf,
Err(_) => return ptr::null_mut(),
};
let view_len = buffer.len();
if view_len < 0 {
unsafe {
PyErr_SetString(
PyExc_TypeError,
c"b64encode() argument has negative length".as_ptr(),
);
}
return ptr::null_mut();
}
let input_len = view_len as usize;
let input = unsafe { slice::from_raw_parts(buffer.as_ptr(), input_len) };
let Some(output_len) = encoded_output_len(input_len) else {
unsafe {
PyErr_NoMemory();
}
return ptr::null_mut();
};
if output_len > isize::MAX as usize {
unsafe {
PyErr_NoMemory();
}
return ptr::null_mut();
}
let result = unsafe {
PyBytes_FromStringAndSize(ptr::null(), output_len as Py_ssize_t)
};
if result.is_null() {
return ptr::null_mut();
}
let dest_ptr = unsafe { PyBytes_AsString(result) };
if dest_ptr.is_null() {
unsafe {
Py_DecRef(result);
}
return ptr::null_mut();
}
let dest = unsafe { slice::from_raw_parts_mut(dest_ptr.cast::<u8>(), output_len) };
let written = encode_into(input, dest);
debug_assert_eq!(written, output_len);
result
}
Все подробности будут в @cpython_notes
Обсуждение: что думаете?
| Поддержать | YouTube | GitHub | Чат |
Discussions on Python.org
Pre-PEP: Rust for CPython
Introduction We (@emmatyping, @eclips4) propose introducing the Rust programming language to CPython. Rust will initially only be allowed for writing optional extension modules, but eventually will become a required dependency of CPython and allowed to be…
❤48👍35🔥31🤡20🤯15😁12👎8😱6💩5🤔4👌2
Находки в опенсорсе
Аллокаторы в СPython: PyArena Один из самых простых аллокаторов в питоне. Исходники. По сути данный аллокатор является небольшой оберткой поверх PyMem_Malloc, но с интересной особенностью. Если PyMem_Malloc имеет PyMem_Free для освобождения памяти каждого…
Аллокаторы в СPython: база
Тема аллокаторов иногда питонистам кажется сложной, потому что в питоне мы их не вызываем явно. Оттого с ними не очень знакомы, так давайте исправлять и знакомиться!
Зачем вообще нужно много разных аллокаторов? Все они делают одно и то же: выделяют память в куче (heap). В зависимости от наших вариантов использования данной памяти - выделять и освобождать её нужно очень по-разному.
Где-то множество мелких объектов, которые часто создаются и очищаются. Где-то несколько больших, которые должны умирать все вместе. Где-то мы работаем в рамках одного потока, где-то несколько потоков будут запрашивать / высвобождать память параллельно.
Например: при парсинге AST мы используем PyArena аллокатор. Он выделяет сразу много памяти, сразу вычищает все за один раз. Что идеально подходит для парсинга.
Но, для рантайма - задачи, конечно же другие. Там есть долгоживущие объекты, есть много мелких краткоживущих, есть довольно большие, есть маленькие. Для таких задач используют "general purpose allocators". Которые в среднем хороши во всем.
Дизайн аллокаторов в CPython
Питон знает, как его будут использовать. Потому поверх базовых GPA есть собственные надстройки.
Документация:
- https://docs.python.org/3/c-api/allocation.html
- https://docs.python.org/3/c-api/memory.html
В CPython есть: malloc, pymalloc, mimalloc и некоторые их варианты для дебага.
Они разделены на три "домена" для аллокаторов, то с чем они работают, какие задачи решают:
-
-
-
Разработчики C-extensions должны понимать, когда какой использовать и под какие задачи.
К счастью, разработчикам на питоне - такое нужно только для любопытства.
А вот таблица, какие реальные аллокаторы используют те или иные C-API функции в разных режимах:
Она правда немного устарела и не отражает Free-Threading сборки, которые требуют mimalloc 🌚
Кто первый успеет сделать PR с исправлением - тот молодец!
О
Зачем питону свой аллокатор?
В CPython есть (был? для free-threading он не используется и не будет) свой аллокатор: pymalloc, основная задача которого – работа с маленькими Python объектами.
Про него полностью тоже нужно писать большой отдельный пост.
Что вообще важно в аллокаторе?
- Стратегия выделения памяти под новый запрос
- Работа с округлениями размера памяти и выравнивание
- Дефрагментация памяти
- Стратегия очистки памяти
Но кратко про
- Он создает арены по 1MB
- Внутри арены разделены на пулы по 16KB
- Внутри пулы поделены на блоки фиксированного размера
Зачем? Чтобы не аллоцировать часто маленькие кусочки памяти. Что дорого.
Можно ли управлять аллокаторами?
Да! Есть опции для сборки:
И даже переменная окружения PYTHONMALLOC, которая позволяет указать, какой аллокатор использовать для всех случаев. Зачем? Прежде всего для дебага. Но можно потестить, вдруг будет давать буст по скорости или потреблению памяти в ваших вариантах использования.
Обсуждение: какой ваш любимый аллокатор? И почему jemalloc?
| Поддержать | YouTube | GitHub | Чат |
Тема аллокаторов иногда питонистам кажется сложной, потому что в питоне мы их не вызываем явно. Оттого с ними не очень знакомы, так давайте исправлять и знакомиться!
Зачем вообще нужно много разных аллокаторов? Все они делают одно и то же: выделяют память в куче (heap). В зависимости от наших вариантов использования данной памяти - выделять и освобождать её нужно очень по-разному.
Где-то множество мелких объектов, которые часто создаются и очищаются. Где-то несколько больших, которые должны умирать все вместе. Где-то мы работаем в рамках одного потока, где-то несколько потоков будут запрашивать / высвобождать память параллельно.
Например: при парсинге AST мы используем PyArena аллокатор. Он выделяет сразу много памяти, сразу вычищает все за один раз. Что идеально подходит для парсинга.
Но, для рантайма - задачи, конечно же другие. Там есть долгоживущие объекты, есть много мелких краткоживущих, есть довольно большие, есть маленькие. Для таких задач используют "general purpose allocators". Которые в среднем хороши во всем.
Дизайн аллокаторов в CPython
Питон знает, как его будут использовать. Потому поверх базовых GPA есть собственные надстройки.
Документация:
- https://docs.python.org/3/c-api/allocation.html
- https://docs.python.org/3/c-api/memory.html
В CPython есть: malloc, pymalloc, mimalloc и некоторые их варианты для дебага.
Они разделены на три "домена" для аллокаторов, то с чем они работают, какие задачи решают:
-
Raw: для выделения памяти для общих задач, например под сишные буферы или IO. Может работать без PyThreadState-
Mem: для выделения памяти для общих задач, но уже с PyThreadState, например под Python буферы, подходит для мелких объектов-
Object: для выделения памяти под конкретные мелкие объектыРазработчики C-extensions должны понимать, когда какой использовать и под какие задачи.
К счастью, разработчикам на питоне - такое нужно только для любопытства.
А вот таблица, какие реальные аллокаторы используют те или иные C-API функции в разных режимах:
PyMem_RawMalloc -> malloc
PyMem_Malloc -> pymalloc
PyObject_Malloc -> pymalloc
Она правда немного устарела и не отражает Free-Threading сборки, которые требуют mimalloc 🌚
Кто первый успеет сделать PR с исправлением - тот молодец!
О
mimalloc мы как-нибудь отдельно поговорим, там нужно рассказывать сильно глубже, в том числе про GC и PyGC_Head.Зачем питону свой аллокатор?
В CPython есть (был? для free-threading он не используется и не будет) свой аллокатор: pymalloc, основная задача которого – работа с маленькими Python объектами.
Про него полностью тоже нужно писать большой отдельный пост.
Что вообще важно в аллокаторе?
- Стратегия выделения памяти под новый запрос
- Работа с округлениями размера памяти и выравнивание
- Дефрагментация памяти
- Стратегия очистки памяти
struct arena_object {
uintptr_t address;
pymem_block* pool_address;
uint nfreepools;
uint ntotalpools;
struct pool_header* freepools;
struct arena_object* nextarena;
struct arena_object* prevarena;
};
Но кратко про
pymalloc можно сказать следующее:- Он создает арены по 1MB
- Внутри арены разделены на пулы по 16KB
- Внутри пулы поделены на блоки фиксированного размера
Зачем? Чтобы не аллоцировать часто маленькие кусочки памяти. Что дорого.
Можно ли управлять аллокаторами?
Да! Есть опции для сборки:
--without-mimalloc, --without-pymallocИ даже переменная окружения PYTHONMALLOC, которая позволяет указать, какой аллокатор использовать для всех случаев. Зачем? Прежде всего для дебага. Но можно потестить, вдруг будет давать буст по скорости или потреблению памяти в ваших вариантах использования.
Обсуждение: какой ваш любимый аллокатор? И почему jemalloc?
| Поддержать | YouTube | GitHub | Чат |
Python documentation
Allocating Objects on the Heap
Deprecated aliases: These are soft deprecated aliases to existing functions and macros. They exist solely for backwards compatibility.,, Deprecated alias, Function,,,, PyObject_New,,, PyObject_NewV...
1🔥71👍30❤9👏2👌1🕊1
git-lfs: храним большие файлы в репозитории правильно
https://www.youtube.com/watch?v=82wj6y2rmR4
Вы сталкивались с проблемой, что рабочий проект клонируется 10 минут?
А когда начинаешь разбираться: почему так? То оказывается, что внутри десятки непережатых картинок для фронта, которые еще и менялись регулярно (а значит, оставили след в истории git навсегда).
Данная проблема влияет не только на локальное использование, ведь мы на самом деле довольно редко делаем
Решение: использовать git-lfs!
Я пригласил замечательного Олега Чирухина @tg_1red2black, чтобы обсудить:
- Как работает git-lfs на базовом уровне?
- Как мигрировать на него с базового сетапа?
- Как он устроен внутри? Поднимаем https://github.com/git-lfs/lfs-test-server и детально смотрим, что там внутри происходит
Ну и конечно чуть-чуть глянули исходники, они, кстати, на #go 🌚️️️️
Обсуждение: как вы храните большие файлы в рабочих проектах? Насколько большие файлы вы храните?
| Поддержать | YouTube | GitHub | Чат |
https://www.youtube.com/watch?v=82wj6y2rmR4
Вы сталкивались с проблемой, что рабочий проект клонируется 10 минут?
А когда начинаешь разбираться: почему так? То оказывается, что внутри десятки непережатых картинок для фронта, которые еще и менялись регулярно (а значит, оставили след в истории git навсегда).
Данная проблема влияет не только на локальное использование, ведь мы на самом деле довольно редко делаем
git clone с нуля, но и самое главное – на скорость всех наших сборок (если мы не используем fetch-depth: 1 или аналог, а использовать их надо). Решение: использовать git-lfs!
Я пригласил замечательного Олега Чирухина @tg_1red2black, чтобы обсудить:
- Как работает git-lfs на базовом уровне?
- Как мигрировать на него с базового сетапа?
- Как он устроен внутри? Поднимаем https://github.com/git-lfs/lfs-test-server и детально смотрим, что там внутри происходит
Ну и конечно чуть-чуть глянули исходники, они, кстати, на #go 🌚️️️️
Обсуждение: как вы храните большие файлы в рабочих проектах? Насколько большие файлы вы храните?
| Поддержать | YouTube | GitHub | Чат |
YouTube
Находки в опенсорсе: git-lfs, не засоряй репозиторий большими файлами зря! #git
GigaCode – AI-ассистент разработчика c агентным режимом. Это полноценный помощник разработчика, способный понимать контекст проекта и выполнять задачи от анализа до готового решения. Ассистент сам открывает нужные файлы, вносит изменения, запускает тесты…
52🔥57👍21❤10👏1
PEP-799: Семплирующий профилировщик встроенный в Python 3.15+
Краткий обзор: https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-sampling-profiler
Документация: https://docs.python.org/3.15/library/profiling.sampling.html
Кратко:
- В 3.15
- В 3.15
- Добавили новый
- А еще добавили встроенные TUI (на скриншоте) и GUI
Ключевые фичи:
- Almost Zero-overhead: добиваемся такого, за счет того, что переодически получаем готовые стектрейсы работающих процессов, не нужно добавлять инструментацию функций как в
- Не нужно менять существующий код
- Разные режимы работы:
- Разные виды замеров:
- Поддержка тредов
- Поддержка asyncio с флагом
- Разные форматы вывода информации:
-
- Поддержка профилирования до уровня опкодов виртуальной машины, включая специализации
- Гибкая конфигурация буквально всего
Примеры запуска:
-
-
На чем основана работа технически?
- PEP-768 с remote-debugging предоставляет техническую возможность быстро и легко получать семплы из виртуальной машины
- Для asyncio используется новый АПИ для async-aware call-graphs
Личное мнение: очень крутая фича, пока у меня вопросы по TUI / GUI. Не очень понимаю, зачем их затащили в stdlib. Зарепортил пару багов. На маке требуется запускать профилировщик с
Кирилл вот тоже заценил.
Обсуждение: Что вы думаете о данной фиче? Как вы сейчас профилируете ваши приложения в разработке и в проде?
P.S. Последний пост в текущем году. Всех с наступающим! 🎄
| Поддержать | YouTube | GitHub | Чат |
Краткий обзор: https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-sampling-profiler
Документация: https://docs.python.org/3.15/library/profiling.sampling.html
Кратко:
- В 3.15
cProfile (написан на C) был перемещен в profiling.tracing- В 3.15
profile (написан на Python) стал deprecated, его уберут в 3.17- Добавили новый
profiling.sampling (кодовое имя `tachyons`), о нем и поговорим- А еще добавили встроенные TUI (на скриншоте) и GUI
Ключевые фичи:
- Almost Zero-overhead: добиваемся такого, за счет того, что переодически получаем готовые стектрейсы работающих процессов, не нужно добавлять инструментацию функций как в
cProfile- Не нужно менять существующий код
- Разные режимы работы:
attach позволяет подключиться к работающему Python процессу, а run позволяет запустить код для профилировки- Разные виды замеров:
--mode wall, --mode cpu, --mode gil, --mode exception- Поддержка тредов
- Поддержка asyncio с флагом
--async-aware, можно смотреть даже suspended tasks с --async-mode=all- Разные форматы вывода информации:
--flamegraph, --pstats, --heatmap, --gecko-
--live вместе с TUI для отображения информации в реальном времени (как в top условном)- Поддержка профилирования до уровня опкодов виртуальной машины, включая специализации
- Гибкая конфигурация буквально всего
Примеры запуска:
-
python -m profiling.sampling run --flamegraph -o profile.html script.py - запускаем скрипты и генерим флеймграф-
python -m profiling.sampling attach --live $YOUR_PID - профилируем работающий процесс и получаем данные в реальном времениНа чем основана работа технически?
- PEP-768 с remote-debugging предоставляет техническую возможность быстро и легко получать семплы из виртуальной машины
- Для asyncio используется новый АПИ для async-aware call-graphs
Личное мнение: очень крутая фича, пока у меня вопросы по TUI / GUI. Не очень понимаю, зачем их затащили в stdlib. Зарепортил пару багов. На маке требуется запускать профилировщик с
sudo -E. Остальное - нравится!Кирилл вот тоже заценил.
Обсуждение: Что вы думаете о данной фиче? Как вы сейчас профилируете ваши приложения в разработке и в проде?
P.S. Последний пост в текущем году. Всех с наступающим! 🎄
| Поддержать | YouTube | GitHub | Чат |
2👍103🔥71❤10🎉4
PEP-800: typing.disjoint_base
ПЕП: https://peps.python.org/pep-0800
Обсуждение: https://discuss.python.org/t/99910
Реализация в
Когда я критикую систему типов в питоне, говоря, что её не продумывали заранее, то
В питоне можно наследоваться от нескольких классов (и вообще всего с методом
Например:
Почему такое происходит почитать можно тут. Но, нам важно узнать, что в CPython есть концепция "solid base", которая считается для всех созданных классов вот тут. Если очень кратко, то CPython должен уметь построить правильный memory-layout для всех классов потомков. Например, все потомки
Иначе - перестанет работать базовая логика
Сделать область памяти для потомка
Но, сделать так можно и со своими классами, не обязательно использовать C, достаточно конфликта в
Подробности из ПЕПа про "solid bases".
Типизация
Теперь
Как следствие, тайпчекеры теперь более четко смогут находить и другие проблемы. Например, в местах где мы создаем "временный" тип:
Раньше такой код проходил в некоторых тайпчекерах. Ведь они думали, что тип подкласс
Отличный ПЕП, система типов стала чуть лучше.
Обсуждение: знали ли вы про solid и disjoint bases в питоне? Стреляли ли себе в ногу таким?
| Поддержать | YouTube | GitHub | Чат |
ПЕП: https://peps.python.org/pep-0800
Обсуждение: https://discuss.python.org/t/99910
Реализация в
typing_extensions: https://github.com/python/typing_extensions/blob/a7610ef567132cac2b5319fa193c830b655364c6/src/typing_extensions.py#L358Когда я критикую систему типов в питоне, говоря, что её не продумывали заранее, то
disjoint_base - отличный пример моих слов.В питоне можно наследоваться от нескольких классов (и вообще всего с методом
__mro_entries__, да). Что иногда довольно удобно, если использовать без фанатизма. Но проблема в том, что не все наборы классов подходят для множественного наследования.Например:
>>> class What(str, int): ...
Traceback (most recent call last):
TypeError: multiple bases have instance lay-out conflict
Почему такое происходит почитать можно тут. Но, нам важно узнать, что в CPython есть концепция "solid base", которая считается для всех созданных классов вот тут. Если очень кратко, то CPython должен уметь построить правильный memory-layout для всех классов потомков. Например, все потомки
int должны быть вот так уложены в памяти:
typedef struct _PyLongValue {
uintptr_t lv_tag; /* Number of digits, sign and flags */
digit ob_digit[1];
} _PyLongValue;
struct _longobject {
PyObject_HEAD
_PyLongValue long_value;
};
Иначе - перестанет работать базовая логика
int. А str устроены по-другому.
/* Object format for Unicode subclasses. */
typedef struct {
PyCompactUnicodeObject _base;
union {
void *any;
Py_UCS1 *latin1;
Py_UCS2 *ucs2;
Py_UCS4 *ucs4;
} data; /* Canonical, smallest-form Unicode buffer */
} PyUnicodeObject;
Сделать область памяти для потомка
int и str сразу - невозможно. Потому и выкидывается ошибка.Но, сделать так можно и со своими классами, не обязательно использовать C, достаточно конфликта в
__slots__:
>>> class A:
... __slots__ = ('a',)
>>> class B:
... __slots__ = ('b',)
>>> class C(A, B): ...
Traceback (most recent call last):
TypeError: multiple bases have instance lay-out conflict
Подробности из ПЕПа про "solid bases".
Типизация
Теперь
int, str и многие другие классы в typeshed помечены как @disjoint_base типы. Значит, что только один такой класс может быть в mro. Раньше такое костылили все тайпчекеры по-своему.Как следствие, тайпчекеры теперь более четко смогут находить и другие проблемы. Например, в местах где мы создаем "временный" тип:
def g(x: int):
match x:
case str(): # unreachable
print("It's both!")
Раньше такой код проходил в некоторых тайпчекерах. Ведь они думали, что тип подкласс
int и str может существовать. А теперь - будут знать, что такое невозможно на уровне определения и выкидывать правильную ошибку.Отличный ПЕП, система типов стала чуть лучше.
Обсуждение: знали ли вы про solid и disjoint bases в питоне? Стреляли ли себе в ногу таким?
| Поддержать | YouTube | GitHub | Чат |
Python Enhancement Proposals (PEPs)
PEP 800 – Disjoint bases in the type system | peps.python.org
To analyze Python programs precisely, type checkers need to know when two classes can and cannot have a common child class. However, the information necessary to determine this is not currently part of the type system. This PEP adds a new decorator, @ty...
4🤔52👍46❤24🔥16🤯5🤡3💩2😱1🕊1