CPython

Материал из llmdocs — справочник разработчика
Портал: Python
CPython
Типреализация языка программирования
ЯзыкPython
Написан наC и Python
Разработчикcore-разработчики Python, Python Software Foundation
Управление памятьюподсчёт ссылок + циклический сборщик мусора
Репозиторийgithub.com/python/cpython
ЛицензияPSF License

CPython — эталонная и самая распространённая реализация языка Python, написанная на языке C. Именно её скачивают с python.org, именно она входит в дистрибутивы Linux и macOS, и именно в ней первыми появляются новые возможности языка. Название подчёркивает язык реализации и отличает её от альтернатив — PyPy, Jython, GraalPy, MicroPython.

История

CPython — исходная реализация, которую Гвидо ван Россум начал писать в 1989 году; название «CPython» появилось позже, когда возникли другие реализации. Долгое время проект жил в системе контроля версий Mercurial, а в 2017 году переехал на GitHub (PEP 512). Разработкой занимаются несколько десятков core-разработчиков, решения о крупных изменениях принимаются через PEP.

Как исполняется код

Запуск программы в CPython проходит несколько стадий:[1]

  1. Токенизация и разбор — исходный текст превращается в абстрактное синтаксическое дерево (AST). С версии 3.9 используется PEG-парсер.
  2. Компиляция — AST переводится в байт-код: последовательность инструкций стековой виртуальной машины, упакованных в объекты кода.
  3. Кеширование — байт-код импортируемых модулей сохраняется в файлы .pyc в каталоге __pycache__ (PEP 3147), чтобы не компилировать их заново.[6]
  4. Интерпретация — главный цикл (ceval.c) выбирает инструкции по одной и исполняет их.

Байт-код можно посмотреть модулем dis:[7]

import dis

def add(a, b):
    return a + b

dis.dis(add)
#   RESUME          0
#   LOAD_FAST_LOAD_FAST  (a, b)
#   BINARY_OP       0 (+)
#   RETURN_VALUE

Точный набор инструкций меняется от версии к версии и не является частью спецификации языка.

Управление памятью

Каждый объект хранит счётчик ссылок; когда он падает до нуля, память освобождается немедленно. Это делает поведение предсказуемым (файл закрывается сразу после потери последней ссылки), но не справляется с циклами — например, двумя объектами, ссылающимися друг на друга. Для них работает дополнительный циклический сборщик мусора по поколениям (модуль gc). Подробнее — в статье Сборка мусора.

GIL и многопоточность

Подсчёт ссылок не потокобезопасен, поэтому исторически CPython защищает интерпретатор глобальной блокировкой (GIL): в каждый момент Python-байт-код исполняет только один поток. Потоки полезны для ввода-вывода (блокировка отпускается при ожидании), но не ускоряют вычисления на нескольких ядрах.

PEP 703 предложил сборку без GIL.[4] В версии 3.13 она появилась как экспериментальная (исполняемый файл python3.13t), в 3.14 получила статус официально поддерживаемой (PEP 779), хотя по умолчанию по-прежнему поставляется сборка с GIL.[5] Подробности — в статье GIL и free-threading (PEP 703).

Ускорение интерпретатора

Начиная с 3.11 проект Faster CPython заметно ускорил интерпретатор:

Версия Изменение
3.11 специализирующий адаптивный интерпретатор (PEP 659): «горячие» инструкции заменяются версиями под конкретные типы[2]
3.12 «бессмертные» объекты (PEP 683), отдельная блокировка на каждый субинтерпретатор (PEP 684)
3.13 экспериментальный JIT-компилятор по схеме copy-and-patch (PEP 744)[3], экспериментальная сборка без GIL
3.14 официально поддерживаемая сборка без GIL, модуль субинтерпретаторов в стандартной библиотеке

C API и расширения

CPython предоставляет C API, через который пишутся модули расширения — так устроены NumPy, драйверы баз данных и многие быстрые библиотеки. Это источник силы экосистемы и одновременно ограничение: альтернативным реализациям трудно поддерживать совместимость с расширениями, завязанными на внутренности CPython. Для генерации расширений используют Cython, pybind11, а для Rust — PyO3.

Сравнение с другими реализациями

Реализация Особенность
CPython эталон, максимальная совместимость с расширениями на C
PyPy трассирующий JIT, быстрее на «чистом» Python, совместимость с C API частичная
MicroPython урезанная реализация для микроконтроллеров
GraalPy на GraalVM, взаимодействие с Java

См. также

Источники

  1. Python Developer's Guide — Internals
  2. PEP 659 — Specializing Adaptive Interpreter
  3. PEP 744 — JIT Compilation
  4. PEP 703 — Making the Global Interpreter Lock Optional in CPython
  5. PEP 779 — Criteria for supported status for free-threaded Python
  6. PEP 3147 — PYC Repository Directories
  7. dis — Disassembler for Python bytecode