TGViewer
Хитрый Питон Хитрый Питон @tricky_python · 3.45K subscribers
Post #210 2.51K

Forwarded from Находки в опенсорсе

`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...
  • 🔥 16
  • 👍 4
More from @tricky_python
  1. Sep 16, 2026Друзья, у нас важное объявление! Некоторые из вас помнят наши курсы Learn Python - когда-т…
  2. Sep 7, 2026В документации Python появилась отдельная страница со сложностью операций над встроенными…
  3. Sep 3, 2026В эту пятницу в 14:00 (по мск) обсудим новости августа в прямом эфире Moscow Python Podcas…
  4. Sep 2, 2026Казалось бы, что может быть проще, чем разбить текст на строки? Может быть, кто-то еще пом…
  5. Aug 31, 2026Пока я был в отпуске и путешествовал, вышел перевод документации Python на русский. Звучит…
  6. Aug 20, 2026Есть такой язык - Mojo: • синтаксически он близок к python • дает возможность вызывать и и…
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 →