TGViewer
Находки в опенсорсе Находки в опенсорсе @opensource_findings · 12.6K subscribers
Post #865 9.67K
`LOAD_CONST` разделили на три опкода в 3.14

https://github.com/python/cpython/pull/125972

В Python 3.14 распилили один из самых популярных опкодов: LOAD_CONST. Он, как можно понять из названия, он загружал константы из frame->co_consts:


// 3.13:
pure inst(LOAD_CONST, (-- value)) {
value = GETITEM(FRAME_CO_CONSTS, oparg);
Py_INCREF(value);
}



>>> def func():
... return 1

>>> func.__code__.co_consts
(None, 1)


Теперь LOAD_CONST разделен на:
- LOAD_SMALL_INT для интов в range(256)
- LOAD_CONST_IMMORTAL для загрузки бесмертных объектов (на 1 Py_INCREF меньше, см PyStackRef_FromPyObjectNew vs `PyStackRef_FromPyObjectImmortal`)
- LOAD_CONST для оставшихся

А еще и RETURN_CONST удалили под шумок.

И вот демо байткода:


>>> import dis
>>> def func():
... x = 1
... y = ...
... z = 'привет, мир'

>>> dis.dis(func, adaptive=True)
2 LOAD_SMALL_INT 1
STORE_FAST 0 (x)

3 LOAD_CONST 1 (Ellipsis)
STORE_FAST 1 (y)

4 LOAD_CONST 2 ('привет, мир')
STORE_FAST 2 (z)
LOAD_CONST 0 (None)
RETURN_VALUE

>>> # Create caches for tier1 adaptive interpreter to work:
>>> for _ in range(100):
... func()
>>> dis.dis(func, adaptive=True)
2 LOAD_SMALL_INT 1
STORE_FAST 0 (x)

3 LOAD_CONST_IMMORTAL 1 (Ellipsis)
STORE_FAST 1 (y)

4 LOAD_CONST 2 ('привет, мир')
STORE_FAST 2 (z)
LOAD_CONST_IMMORTAL 0 (None)
RETURN_VALUE


Зачем нужен LOAD_SMALL_INT?

https://github.com/python/cpython/issues/101291

Если вы внимательно смотрели мой видос про 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;
};


Большие и сложные объекты. Но, для очень частых маленьких чисел, такое переусложнение замедляет работу. Мы можем просто представлять числа в рамках одного машинного слова и складывать их сразу в oparg, без необходимости заргужать их из co_consts:


op(_LOAD_SMALL_INT, (-- value)) {
PyObject *val = PyLong_FromLong(this_instr->oparg);
value = sym_new_const(ctx, val);
}


В Python2, кстати, работало быстрее, потому что там был честный int тип.

Обсуждение

Задумываетесь ли вы про подобные микро-оптимизации, когда пишите код?
GitHub GH-125837: Split `LOAD_CONST` into three. by markshannon · Pull Request #125972 · python/cpython Splits LOAD_CONST into three instructions LOAD_INT for ints in range(256). Avoids the need for a space in the co_consts tuple and avoids an incref LOAD_CONST_IMMORTAL for other immortal objects. A...
  • ❤ 36
  • 👍 9
  • 👌 2
More from @opensource_findings
  1. Sep 28, 2026Еще анонсы докладов на бесплатную конференцию 17 октября в НН Регистрация: https://itgorky…
  2. Sep 25, 2026Монадические выражения в Python. Наконец-то! Продолжаем разговор про интересные PEPы. Пого…
  3. Sep 15, 2026PEPы в Python окончательно вышли из-под контроля Давайте посмотрим, что происходит с ПЕПам…
  4. Sep 10, 2026Большая бесплатная конференция в Нижнем Новгороде 17 октября Регистрация: https://itgorky.…
  5. Sep 1, 2026Post #985
  6. Aug 24, 2026JIT могут удалить из CPython! PEP-836: https://peps.python.org/pep-0836 JIT в CPython имее…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →