Как устроен Python под капотом: полный разбор внутренней архитектуры CPython

Python кажется простым языком: написал строку — получил результат.
Но внутри работает сложная машина, состоящая из парсера, компилятора, виртуальной машины, менеджера памяти и целого набора низкоуровневых структур данных.


t.me/ai_machinelearning_big_data – мой тг канал, где я объяcняю сложные концепции и код с помощью короткий видео и картинок

Разберём всё по шагам.


1. Лексер и Парсер

Когда вы запускаете Python-файл, код проходит три этапа:

➤ 1) Лексер

Преобразует текст в токены: идентификаторы, числа, ключевые слова, операторы.

x = 1 + 2

Превращается в:

NAME(x)
EQUAL
NUMBER(1)
PLUS
NUMBER(2)
NEWLINE

➤ 2) Парсер

Токены собираются в синтаксическое дерево (AST — Abstract Syntax Tree).

Пример узла AST:

Assign(
   targets=[Name(id='x')],
   value=BinOp(1 + 2)
)

AST — структурированное дерево, описывающее, что именно делает программа.


2. Компилятор → Байткод (Bytecode)

CPython компилирует AST в байткод, который выполняет виртуальная машина Python.

Пример:

x = 1 + 2

Компилируется в:

LOAD_CONST 1
LOAD_CONST 2
BINARY_ADD
STORE_NAME x

Этот байткод хранится в объекте code object, который вы можете увидеть сами:

import dis
dis.dis(lambda: 1 + 2)

3. Виртуальная машина Python (Python Virtual Machine)

CPython — это стековая виртуальная машина.
Каждая инструкция байткода — маленькая операция, которая работает поверх стека.

Пример:

LOAD_CONST 1   → пушит 1 на стек  
LOAD_CONST 2   → пушит 2  
BINARY_ADD     → снимает две верхние, складывает, кладёт обратно  
STORE_NAME x   → снимает верхнюю и привязывает к имени

Виртуальная машина — это цикл:

while True:
    instruction = next opcode
    execute(instruction)

Это называется Interpreter Loop или eval loop.


4. Объектная модель Python

Всё в Python — объект.
Даже числа, списки, функции — всё является структурой PyObject на C.

У каждого объекта есть:

  • счётчик ссылок (для автоматического управления памятью)
  • тип (PyTypeObject)
  • реальные данные

Например, число 42 в CPython — это:

PyLongObject {
    ob_refcnt = …
    ob_type = &PyLong_Type
    value = 42
}

5. Управление памятью: Reference Counting + GC

Python использует два механизма:

✓ 1) Reference Counting

Каждый объект хранит число ссылок.
Когда счётчик падает до нуля — объект уничтожается.

a = [1,2,3]
b = a
del a
del b  # объект удалён

✓ 2) Garbage Collector (GC)

Нужен для обнаружения циклов, которые невозможно уничтожить через refcount.

GC работает поколениями (generational GC).


6. GIL — Global Interpreter Lock

Самая обсуждаемая особенность CPython.
GIL гарантирует, что одновременно байткод исполняет только один поток.

Проблемы:

  • CPU-bound код не ускоряется потоками
  • сложная конкуренция между потоками

Преимущества:

  • простая безопасность памяти
  • отсутствие race conditions внутри VM
  • упрощённый C API

Для CPU задач используют:

  • multiprocessing
  • C-расширения без GIL
  • PyPy, GraalPython, Mojo

7. Как работают модули и расширения

CPython легко расширяется — модули можно писать на C, C++ и Rust.

Пример C-функции:

static PyObject* add(PyObject* self, PyObject* args) {
    int a, b;
    PyArg_ParseTuple(args, "ii", &a, &b);
    return PyLong_FromLong(a + b);
}

Такие модули выполняются намного быстрее, чем Python-код.


8. Как работает импорт

При импорте Python делает:

  1. ищет модуль в sys.modules
  2. ищет файл (py / pyc / so / dll)
  3. компилирует .py → .pyc
  4. загружает объект модуля
  5. выполняет код модуля

Bytecode кешируется в __pycache__/.


9. PyPy, Cython, Numba — другие механики исполнения

CPython — не единственная реализация.

PyPy

JIT-компилятор, умеет разгонять Python-код в 3–6 раз.

Cython

Статическая компиляция Python-подобного кода в C.

Numba

JIT-компиляция функций для вычислений (LLVM).


10. Почему Python медленный?

Причины:

  • интерпретируемый байткод
  • GIL блокирует параллельность
  • каждый объект — тяжёлый PyObject
  • динамическая типизация требует проверок
  • VM использует стековые операции (дороже регистровых)

Но Python даёт скорость разработки, и тяжёлые участки легко вынести в C или Rust.


Итог: как Python выполняет ваш код

  1. Текст → токены
  2. Токены → AST
  3. AST → байткод
  4. ВМ исполняет байткод
  5. Объекты управляются refcount + GC
  6. GIL синхронизирует исполнение
  7. Модули и расширения ускоряют вычисления

Python прост снаружи, но внутри — это мощная и очень гибкая архитектура.

+1
0
+1
0
+1
1
+1
1
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *