Member
Rating
Created At
Привет! Меня зовут Никита Соболев. Я занимаюсь опенсорс разработкой полный рабочий день. Тут я рассказываю про #python, #c, интересные проекты, коммиты, доклады, и тд.Поддержать: https://boosty.to/sobolevnДля связи: @sobolev_nikita
No related blogs yet
PEP-747: TypeForm, или "аннотируем аннотации"
PEP: https://peps.python.org/747
Реализация: https://github.com/python/cpython/pull/145034
Что и зачем?
Представьте, что вам нужно описать, что какая-то функция может принять в качестве входного аргумента любую аннотацию. Например для валидации как в пидантике. Как бы вы такое сделали?type[T]?
from typing import Any
def validate[T](typ: type[T], value: Any) -> None: ...
validate(int, 1)
typ будет ожидать любой объект класса type, а не любую аннотацию.int | str не является объектом класса type, но является валидной аннотацией. Так же как и: None, Literal[1], Self, T, тд.ResponseSpec(return_type=int | str, status_code=200) для такого кода пользователя:
from dmr import Controller
from dmr.plugins.msgspec import MsgspecSerializer
class UserController(Controller[MsgspecSerializer]):
async def get(self) -> int | str: ...
ResponseSpec.return_type имеет аннотацию Any, как единственный рабочий вариант. TypeForm[Any] в ближайшее время.
from typing_extensions import TypeForm, Any
def validate[T](typ: TypeForm[T], value: Any) -> T: ...
reveal_type(validate(int, 1)) # int
reveal_type(validate(int | str, 1)) # int | str
typing_extensions код уже есть, поддержка в mypy будет в версии 1.20 (следующей).typing. TypeForm есть у вас? Python Enhancement Proposals (PEPs)
PEP 747 – Annotating Type Forms | peps.python.orgType expressions provide a standardized way to specify types in the Python type system. When a type expression is evaluated at runtime, the resulting type form object encodes the information supplied in the type expression. This enables a variety of use...
PEP-814: frozendict
В Python 3.15 появится полноценный иммутабельный словарь.
PEP: https://peps.python.org/pep-0814
Обсуждение: https://discuss.python.org/t/pep-814-add-frozendict-built-in-type/104854
Оригинальный PR: https://github.com/python/cpython/pull/144757
Исходники (да, они с dict лежат в одном файле на 8к строк)
Зачем?
Главный вопрос: зачем питону вдруг через 35 лет понадобился иммутабельный словарь? Мотивации в ПЕПе явно не очень хватает. Но я докину:
1. frozendict можно будет шарить между разными интерпретаторами без какого-либо оверхеда
2. С иммутабельными объектами куда проще работать в режиме Free-Threading
3. Многие другие новые идеи вроде Виртуальных Потоков тоже хотели бы иметь аналог иммутабельного словаря
Ну а types.MappingProxyType(mapping) был только surface-immutable. Все равно можно было поменять оригинальный объект mapping.
И вот у нас появилась точная копия обычного dict, только иммутабельная:
Примерыfrozendict является collections.abc.Mapping и таким же Generic с двумя параметрами:
>>> frozendict.__mro__
(<class 'frozendict'>, <class 'object'>)
>>> obj = frozendict({'a': 1})
>>> frozendict[str, int]
frozendict[str, int]
collections.abc.MutableMapping:
>>> obj['a'] = 2
TypeError: 'frozendict' object does not support item assignment
>>> obj.update
AttributeError: 'frozendict' object has no attribute 'update'
hash, если все ключи и значения умеют в hash:
>>> hash(obj)
6343282633043897990
>>> hash(frozendict({1: []}))
TypeError: unhashable type: 'list'
>>> obj = frozendict({'a': 1})
>>> id(obj)
4352339472
>>> obj |= {'b': 2} # <- тут мы создали новый frozendict
>>> obj
frozendict({'a': 1, 'b': 2})
>>> id(obj)
4352341680
frozendict просто переиспользует clinic макросы dict для определения своих методов (=использует те же методы):
static PyMethodDef frozendict_methods[] = {
DICT___CONTAINS___METHODDEF
{"__getitem__", dict_subscript, METH_O | METH_COEXIST, getitem__doc__},
DICT___SIZEOF___METHODDEF
DICT_GET_METHODDEF
DICT_KEYS_METHODDEF
DICT_ITEMS_METHODDEF
DICT_VALUES_METHODDEF
DICT_FROMKEYS_METHODDEF
DICT_COPY_METHODDEF
DICT___REVERSED___METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL} /* sentinel */
};
hash: он полностью дублирует алгоритм хеша из frozenset.PyFrozenDict_New, PyAnyDict_Check проверяет на dict, frozendict или их подтипы.dict на frozendict.Python Enhancement Proposals (PEPs)
PEP 814 – Add frozendict built-in type | peps.python.orgA new public immutable type frozendict is added to the builtins module.
Обстановка в опенсорсе прямо сейчас: https://github.com/wemake-services/wemake-python-styleguide/issues/3596
А пока - все вместе ждем релиза django_modern_rest, уже скоро.

PEP-800: typing.disjoint_base
ПЕП: 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
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 сразу - невозможно. Потому и выкидывается ошибка.__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
int, str и многие другие классы в typeshed помечены как @disjoint_base типы. Значит, что только один такой класс может быть в mro. Раньше такое костылили все тайпчекеры по-своему.
def g(x: int):
match x:
case str(): # unreachable
print("It's both!")
int и str может существовать. А теперь - будут знать, что такое невозможно на уровне определения и выкидывать правильную ошибку.Python Enhancement Proposals (PEPs)
PEP 800 – Disjoint bases in the type system | peps.python.orgTo 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...
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 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 | Чат |

git-lfs: храним большие файлы в репозитории правильно
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, не засоряй репозиторий большими файлами зря! #gitGigaCode – AI-ассистент разработчика c агентным режимом. Это полноценный помощник разработчика, способный понимать контекст проекта и выполнять задачи от анализа до готового решения. Ассистент сам открывает нужные файлы, вносит изменения, запускает тесты…
Аллокаторы в С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 и некоторые их варианты для дебага.
Они разделены на три "домена" для аллокаторов, то с чем они работают, какие задачи решают:
- Raw: для выделения памяти для общих задач, например под сишные буферы или IO. Может работать без PyThreadState
- Mem: для выделения памяти для общих задач, но уже с PyThreadState, например под Python буферы, подходит для мелких объектов
- Object: для выделения памяти под конкретные мелкие объекты
Разработчики C-extensions должны понимать, когда какой использовать и под какие задачи.
К счастью, разработчикам на питоне - такое нужно только для любопытства.
А вот таблица, какие реальные аллокаторы используют те или иные C-API функции в разных режимах:
PyMem_RawMalloc -> malloc
PyMem_Malloc -> pymalloc
PyObject_Malloc -> pymalloc
mimalloc мы как-нибудь отдельно поговорим, там нужно рассказывать сильно глубже, в том числе про GC и PyGC_Head.
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 можно сказать следующее:--without-mimalloc, --without-pymallocPython documentation
Allocating Objects on the HeapDeprecated aliases: These are soft deprecated aliases to existing functions and macros. They exist solely for backwards compatibility.,, Deprecated alias, Function,,,, PyObject_New,,, PyObject_NewV...
Breaking news
В 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
}
Discussions on Python.org
Pre-PEP: Rust for CPythonIntroduction 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…
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
"custom-ui-style.stylesheet": {
"#status\\.problems": {
"visibility": "hidden !important",
"display": "none !important",
}
}
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]
}
YouTube
Гайд по кастомизации vscode: чистим status bar, пишем плагины на #javascript– Мой телеграм канал: https://t.me/opensource_findings
– Поддержать: https://boosty.to/sobolevn
– Мой GitHub: https://github.com/sobolevn
– Прислать материал для видео: https://t.me/opensource_findings_chat
Максимальная продуктивность и минимализм в visual…


PEP 810: Explicit lazy imports
На обсуждение вышел новый 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/96755LazyLoader и страшных вещей вроде 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 получит флаг, является ли импорт ленивымimport * не будет доступен в lazy режиме.
# SyntaxError: lazy from ... import * is not allowed
lazy from json import *
django-modern-rest. Простую и удобную библиотеку для REST API в Django. Пока на стадии pre-alpha, но уже скоро будет первый релиз. Можно уже ставить ⭐, чтобы потом всем говорить, что первыми узнали про новую модную штуку!Python Enhancement Proposals (PEPs)
PEP 810 – Explicit lazy imports | peps.python.orgThis PEP introduces syntax for lazy imports as an explicit language feature:
Минусы 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 в качестве моделейadvanced_sqlalchemy, очень удобно для крудов)v3 (или которые все еще будут с нами)
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 и в параметрах может не совпасть. Есть некоторая валидация для такого в рантайме, но все равно очень рисково. v3, ваши голоса – могут помочь :) app.state, что очень криво. Данная проблема признана ошибкой дизайна и будет исправлено в v3, ура!pydantic.Json не обработан, имеет кривую схему. Сейчас мы обсуждаем стоит ли откатиться до дефолтной схемы. Стоит ли?PydanticPlugin игнорирует ConfigDict, который объявлен в самой моделе, в v3 будет пофикшено. Сейчас параметры вроде by_alias и round_trip надо передавать в плагин. Что свело меня с ума, искал ошибку несколько часовv3: https://github.com/litestar-org/litestar/issues/4009GitHub
litestar-org/litestarLight, flexible and extensible ASGI framework | Built to scale - litestar-org/litestar
pinned «»
Большая бесплатная Python конференция в Нижнем Новгороде! У меня хорошая новость. Делаем бесплатную конфу по питону, пригласили топовых специалистов: core-разработчиков, контрибьюторов, организаторов разных комьюнити движух, специалистов из индустрии. И все…
Записи с нашей бесплатной конфы в Нижнем подъехали!
Во-первых, хочу еще раз повторить слова благодарности всем: организаторам и волонтерам, спикерам, участникам. Отдельно хочу отметить тех, кто поддержал конфу анонсами. Приехало и пришло очень много людей: 1100+ регистраций, почти 600 человек на площадке. Вы все крутые!
Во-вторых, в программе случились две замены. Ждем ребят, кто не смог приехать, на будущих мероприятиях.
Постарался найти баланс между хардкорнейшими докладами, спикерами-новичками (они обязательно должны быть на любой конференции, по моему мнению, я когда-то был таким спикером-новичком) и легкими погружениями в технологии.
Конкуренция за звание "лучшего" доклада – высочайшая. Выбирать будем не по каким-то там голосованиям, которые ни на что не влияют, а по просмотрам на ютюбе. Поддержите спикеров и меня просмотрами :)
Выкладываю записи сразу, а не через полгода.
Доклады в порядке выступлений:
- Чего вы не знали о строках в Python? Василий Рябов
- ИИ-агенты в каждый дом, Алексей Порядин @sw1logs
- Генератор байткода и байткод генератора, Михаил Ефимов
- Внутреннее устройство сборки мусора в CPython 3.14+, Сергей Мирянов
- Проектирование — это когда чувствуешь, а не какие-то там циферки, Николай Хитров @nkhitrov_blog
- Дотянуться до кремния. HighLoad Python: SIMD, GPU – Пётр Андреев @py_up
- Continuous profiling, Давид Джалаев @dzhalaevd_blog
- Vim — это метаредактирование, Илья Ильиных @kydavoiti
Но, на конфе были и минусы :)
Следующий раз постараемся поправить шум от стендов (мешали в большом зале), записать все доклады (сейчас только один зал), пригласить еще больше гостей.
Наша традиционная вечеринка собрала полный бар людей, было очень весело. Отлично посидели, погуляли, поболтали. Лучшее сообщество!
При поддержке:
- https://it52.info
- https://itgorky.ru
Обсуждение: Кто был? Как вам конфа? Как вам Нижний Новгород?
Если понравилось: напишите приятное организаторам и спикерам. Если не понравилось – пишите вашу критику. Будем делать лучше.
| Поддержать | YouTube | GitHub | Чат |
Набор новых интересных PEPов и обсуждений для 3.15+
Сегодня будет пост для тех, кто любит заглядывать в будущее.
Поговорим про то, что только-только начинают делать в питончике.
JIT и FT
https://github.com/python/cpython/issues/139038
Описывает планы на 3.15 и 3.16 по развитию JIT.
Самое важное планируют:
- Сделать JIT на 5-10% быстрее для всех случаев, до 50% скорости для краевых случаев
- Трассирующий JIT: https://github.com/python/cpython/issues/139109
- Поддежка Free-Threading режима: https://github.com/python/cpython/issues/133171
- К 3.16 планируют найти еще 2х меинтейнеров, потому что сейчас очень мало людей работают над джитом. Если всегда хотели - присоединяйтесь!
https://discuss.python.org/t/pre-pep-safe-parallel-python/103636
Обсуждение по будущему FT и subinterpreters как практических концепций.
Марк Шеннон предлагает сделать из Python Erlang 🌚
Каждому объекту предлагают добавить:
- Метод __freeze__() в большинство классов, чтобы делать объект иммутабельным (чтобы можно его было шарить между потоками и интерпретаторами)
- Метод __protect__(self: Self, obj: T) -> T, чтобы помечать объекты как "защищенные". Их можно менять, но с мьютексом
- И сам __mutex__, чтобы работать с защищенными объектами
https://discuss.python.org/t/add-virtual-threads-to-python/91403
Еще одно предложение от Марка – virtual threads в Python!
Кажется, что не только мне не нравится asyncio.
Обсуждение на очень раннем шаге, можно принять участие :)
PEPs
https://peps.python.org/pep-0798 позволит нам писать вот такой код:
list_of_lists = [[1, 2], [3, 4]]
flat_list = [*l for l in list_of_lists]
profiling в CPythonprofile теперь deprecatedprofiling.sampling cProfile теперь будет доступен еще и как profile.tracingTypedDict:
class Movie(TypedDict, extra_items=str):
name: str
rating: float
year: int
str. Что удобно, если у нас гигантский json с кучей похожих полей, например.
class Movie(TypedDict, closed=True):
name: str
rating: float
year: int
intmathmath. Если интересуетесь математикой в питоне – ПЕП для вас.GitHub
JIT Planning for 3.15 and 3.16 · Issue #139038 · python/cpythonFollowing a conversation at the CPython Core Dev Sprint, this is an uber issue tracking JIT performance goals and planning for 3.15 and 3.16. The goal here is to capture our goals and the work that...
Находки в опенсорсе: EasyP – тулбокс для ProtoBuf файлов
https://www.youtube.com/watch?v=XI-dNpM77iMeasyp – пакетный менеджер, билд-система и линтер для .proto файлов.
Хоть easyp и написан на #go 😱, одна из его фишек в том – что вы можете использовать любые плагины для генерации финального кода: он может быть хоть на #python, хоть на #rust.
Если много используете ProtoBuf – обязательно для ознакомления!
Как оно работает?
# Секция для правил линтера:
lint:
use:
- DEFAULT
# Секция с зависимостями:
deps:
- github.com/googleapis/googleapis
- github.com/grpc-ecosystem/grpc-gateway@v2.20.0
# Секция для правил сборки и генерации итоговых файлов:
generate:
plugins:
- name: go
out: .
opts:
paths: source_relative
- name: go-grpc
out: .
opts:
paths: source_relative
require_unimplemented_servers: false
Makefile с кучей скриптов для сборки.YouTube
Находки в опенсорсе: EasyP – тулбокс для работы с ProtoBuf- Мой телеграм канал: https://t.me/opensource_findings
- Наш чат, где можно обсудить выпуск: https://t.me/opensource_findings_chat
- Поддержать: https://boosty.to/sobolevn
- Мой GitHub: https://github.com/sobolevn
EasyP – тулбокс для работы с ProtoBuf файлами.…
`__typing_subst__` – магический метод в Python, про который вы не слышали
В питоне сложилась довольно сложная ситуация с типизацией. В отличии от многих других языков, у нас нет специального "мини-языка типов". Что сильно упрощает работу с типизацией для авторов языка. Ведь им не нужно поддерживать поведение объектов типизации в рантайме.
А у нас есть только старый добрый питон и его объекты. Да, в питоне – действительно всё объект. Даже типизация. Оттого, любой код, который вы пишите в аннотациях – должен корректно работать в рантайме. Ведь у нас есть потребители такого, например: pydantic.
Скажем, у нас есть TypeAliasType объект с одной типовой переменной. Мы хотим её явно указать:
type StrDict[_V] = dict[str, _V]
numbers: StrDict[int] = {'one': 1}
StrDict[int] вызовет __getitem__ вот тут. Кстати, там Cшный код, конечно же. И нам просто вернется нужный GenericAlias объект с нужными __args__:
>>> type StrDict[_V] = dict[str, _V]
>>> StrDict[int], type(StrDict[int]), StrDict[int].__args__
(StrDict[int], <class 'types.GenericAlias'>, (<class 'int'>,))
_V на int работает! Пока что 🌚TypeVar, TypeVarTuple, ParamSpec. У каждого из них есть свои правила, как можно их заменять (в некоторых контекстах):TypeVar можно заменять на одно другое типовое значениеTypeVarTuple можно заменять на любое количество типовых значенийParamSpec можно заменять на Concatenate, ... и список типов
>>> from collections.abc import Callable
>>> from typing import ParamSpec, TypeVar
>>> P = ParamSpec('P')
>>> R = TypeVar('R')
>>> Callable[P, R][0, int]
Traceback (most recent call last):
TypeError: Expected a list of types, an ellipsis, ParamSpec, or Concatenate. Got <class 'int'>
P на 0, что не является корректной заменой.__typing_subst__.ParamSpec.__typing_subst__ вызывает typing._paramspec_subst. Почему так? В 3.12 все переписали на C в спешке. Но некоторые части были слишком сложны, их оставили на питоне.
>>> P.__typing_subst__([])
()
>>> P.__typing_subst__([int, str])
(<class 'int'>, <class 'str'>)
>>> P.__typing_subst__(...)
Ellipsis
>>> P.__typing_subst__(0)
Traceback (most recent call last):
TypeError: Expected a list of types, an ellipsis, ParamSpec, or Concatenate. Got 0
__typing_prepare_subst__. Он нужен, чтобы собрать аргументы для замены. Потому что у нас, например, могут быть неявные аргументы с default. Проверим на TypeVarTuple:
>>> class Custom[T1, *Ts=(int, int)]: ...
...
>>> Custom[str]
__main__.Custom[str, [int, int]]
>>> Custom[str, str]
__main__.Custom[str, str]
>>> Custom.__type_params__[1].__typing_prepare_subst__(*Custom.__type_params__[1], ())
([(<class 'int'>, <class 'int'>)],)
>>> Custom.__type_params__[1].__typing_prepare_subst__(*Custom.__type_params__[1], (str,))
((<class 'str'>,),)
[int, int] нам как раз добавили в __args__ через __typing_prepare_subst__ вот тут.Generic с параметрами. Потому с 3.14 все аннотации будут ленивыми по-умолчанию. А __annotate__ будет выполняться только тогда, когда аннотации будут запрашивать реально для рантайма.Python documentation
typing — Support for type hintsSource code: Lib/typing.py This module provides runtime support for type hints. Consider the function below: The function surface_area_of_cube takes an argument expected to be an instance of float,...
minimal vscode: убираем Activity и Side Bars https://www.youtube.com/watch?v=wxbifNb1Q1o Одни из главных потребителей места на мониторе: Activity Bar и Side Bar. Их настолько просто убрать, чтобы оставалось больше места для кода, что я не вижу причин НЕ…
minimal vscode: убираем вкладки
https://www.youtube.com/watch?v=reT_wnDSaX4
Вкладки любят делать вид, что они очень полезны. Однако, такое впечатление обманчиво. Навигация по ним будет съедать у вас кучу времени. Взамен – есть способы лучше.
Что будет в видео?
- Как убрать вкладки?
- Как сделать заголовок вкладки читаемым?
- Что использовать вместо вкладок?
- Какие способы навигации удобнее вкладок?
Пельмени
Пельмени? Пельмени!
А еще в середине видео я решил попиарить свои любимые пельмени из родного Новосибирска. А мы там знаем толк в пельменях. Если вы не сидите в нашем чате, то вы пропустили все мемы про пельмени, и откуда вообще такая тема пошла :)
Сделал для вас набор рецептов для их приготовления от самого простого уровня до довольно замороченного: github.com/sobolevn/the-best-python-course/tree/main/minimal_vscode/dumplings
Рецепты написаны на языке Cooklang: https://cooklang.org
Специальный язык для разметки рецептов + среда для рендеринга рецептов в терминале и в виде сайтика.
Очень прикольная штука, выглядит вот так:
Положите пельмени в воду, варите пока не всплывут все пельмени и еще ~{7%min} после.
Главное – не переварить, блин!
При подаче смешайте @кетчуп и @майонез в качестве соуса.
YouTube
Гайд по кастомизации vscode: удобная навигация вместо вкладок– Мой телеграм канал: https://t.me/opensource_findings
– Поддержать: https://boosty.to/sobolevn
– Мой GitHub: https://github.com/sobolevn
– Прислать материал для видео: https://t.me/opensource_findings_chat
Максимальная продуктивность и минимализм в visual…
Три типа объектов в Питоне
В питоне часто любят обсуждать "мутабельные" и "иммутабельные" объекты, но крайне редко объясняют, в чем же на самом деле разница. Сегодня мы посмотрим на такое со стороны C.
PyObject
Все мы знаем, что в питоне все объект или PyObject *, который упрощенно выглядит так (в FT сборке он посложнее):
struct _object {
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
}
>>> class A:
... __slots__ = ()
>>> class B:
... __slots__ = ()
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__ = B
>>> type(a)
<class '__main__.B'>
None: ob_refcnt не меняется (immortal), тип менять нельзя, ведь Py_TPFLAGS_IMMUTABLETYPE установлен (static type), размер неизменный 0 для всех потенциальных значенийint: ob_refcnt может меняться для больших чисел (маленькие инты - immortal), тип менять нельзя, размер нельзя менять, но он будет разный для разных чисел:
>>> sys.getsizeof(1)
28
>>> sys.getsizeof(10000000000000)
32
list: ob_refcnt всегда меняется, тип менять нельзя, размер меняетсяPyObject ничего такого нет.
struct PyVarObject {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
};
#define PyObject_HEAD PyObject ob_base;
#define PyObject_VAR_HEAD PyVarObject ob_base;
ob_size, аллоцируем новую память (если нужно) под новые объекты внутри.
typedef struct {
PyObject_VAR_HEAD
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item;
/* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
*/
Py_ssize_t allocated;
} PyListObject;
list (и многие другие) не просто PyObject, они:PyListObjectPyVarObjectPyObjectNone не имеет внутреннего состояния вообще (не использует ничего)int может иметь разный размер, но не может изменяться, потому использует PyObject_HEAD (раньше был PyObject_VAR_HEAD, там сложная история):
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;
};
list может иметь разный размер и может изменятся, потому использует PyObject_VAR_HEAD, как я показывал вышеlen() для list? Python documentation
Common Object StructuresThere are a large number of structures which are used in the definition of object types for Python. This section describes these structures and how they are used. Base object types and macros: All ...