Интерпретатор Python
Компилируемые и интерпретируемые языки программирования
Языки программирования высокого уровня ближе к человеческому языку, чем к машинному. А процессор понимает только машинный код. Поэтому программу, написанную на таком языке, нужно перевести в машинный код. Такими переводчиками стали компиляторы и интерпретаторы. Исторически все высокоуровневые языки делят на компилируемые и интерпретируемые.
Если язык компилируемый, например C, то написав код программы, вы вначале компилируете его, то есть целиком переводите в машинный код. В результате получается бинарный файл, который можно выполнять. Такие файлы платформозависимы: для другой операционной системы или другого типа процессора код нужно компилировать заново. Зато работают они очень быстро, ведь в них уже записан машинный код, который процессор выполняет напрямую.
Если язык интерпретируемый, например Python, то программа это просто текстовый файл с кодом, а выполняет его другая программа — интерпретатор. Поэтому написанный код будет работать в любой операционной системе и на любом процессоре, главное чтобы там был установлен интерпретатор этого языка. Это называется кроссплатформенность. Но выполнение такой программы медленнее, ведь интерпретатор сам тратит время на разбор и выполнение кода.
Важное уточнение: такое деление условное. Правильнее говорить не о языке, а о его реализации. Для одного языка могут существовать и интерпретаторы, и компиляторы. А в «интерпретируемом» Python, как мы сейчас увидим, компилятор тоже есть.
Интерпретатор Python
Как вы уже поняли, обычно Python называют интерпретируемым языком. Это означает, что для запуска программы на Python в системе должен быть установлен интерпретатор Python. В большинстве дистрибутивов Linux он уже есть, проверить версию можно так:
$ python3 --version
Python 3.13.16
Код выполняет не процессор, а именно интерпретатор. Чтобы запустить программу, вы обычно выполняете такую команду:
$ python3 program.py
То есть вы просите интерпретатор (python3) выполнить код, написанный в файле (program.py). Интерпретатор читает файл, выполняет его и выдаёт нам результат.

Но давайте поближе познакомимся с интерпретатором Python, ведь он не так прост, как кажется.
Распространённое заблуждение: «интерпретатор берёт строку кода, переводит её в машинный код, выполняет, потом берёт следующую». На самом деле всё устроено сложнее. Внутри интерпретатора есть компилятор, который переводит код на Python не в машинный код, а в байт-код. И есть виртуальная машина, которая этот байт-код выполняет.
Байт-код это набор простых инструкций для виртуальной машины Python. Это не машинный код, поэтому напрямую процессор его не выполняет. Но он гораздо проще исходного кода, а значит интерпретатору его выполнять быстрее. Кроме того, байт-код не зависит от операционной системы и типа процессора.
Виртуальная машина, которая выполняет байт-код, встроена в интерпретатор. Её называют Python VM или PVM. По сути, это большой цикл, который берёт инструкции байт-кода по одной и выполняет их.
Теперь схема становится более интересной, ведь мы знаем, что внутри интерпретатора работают компилятор и виртуальная машина:

- Мы просим интерпретатор (python3) выполнить программу (program.py).
- Интерпретатор читает файл и отдаёт код компилятору.
- Компилятор создаёт байт-код.
- Виртуальная машина (PVM) выполняет этот байт-код.
- В конце мы получаем результат.
Интерпретатор, который устроен по такой схеме и написан на языке C, называется CPython. Это основная, или как говорят, эталонная реализация Python. Именно её вы скачиваете с python.org и ставите из пакетов дистрибутива. Когда в статьях пишут просто «Python», почти всегда имеют в виду CPython.
Смотрим байт-код своими глазами
Байт-код можно посмотреть. Для этого в стандартной библиотеке есть модуль dis (от англ. disassembler). Возьмём простую функцию:
def add(a, b):
return a + b
И посмотрим, во что её превратил компилятор:
$ python3 -m dis helper.py # на Windows py -m dis helper.py
...
Disassembly of <code object add at 0x7f6b650f8570, file "helper.py", line 1>:
1 RESUME 0
2 LOAD_FAST_LOAD_FAST 1 (a, b)
BINARY_OP 0 (+)
RETURN_VALUE
Читается это просто:
- LOAD_FAST_LOAD_FAST — загрузить в стек значения
aиb; - BINARY_OP (+) — сложить два значения;
- RETURN_VALUE — вернуть результат.
Набор инструкций байт-кода меняется от версии к версии Python. Поэтому на вашей версии вывод может немного отличаться (я запускал на Python 3.13). Это нормально, учить инструкции наизусть не нужно, главное понять идею.
Каталог pycache
Теперь поговорим о каталоге __pycache__, который наверняка вы видели рядом со своими программами. Давайте разберёмся на примере. Создадим два файла.
Файл helper.py с функцией:
def add(a, b):
return a + b
И файл program.py, который эту функцию использует:
import helper
print("main", helper.add(2, 3))
Запустим программу и посмотрим, что появилось в каталоге:
$ python3 program.py
main 5
$ ls -R
.:
helper.py __pycache__ program.py
./__pycache__:
helper.cpython-313.pyc
Обратите внимание на два момента:
- Файл program.pyc не появился. Байт-код сохраняется только для импортируемых модулей (у нас это helper.py). Файл, который вы запускаете напрямую, компилируется в памяти при каждом запуске, а на диск не записывается.
- В имени helper.cpython-313.pyc указана реализация и версия Python (cpython-313 это CPython 3.13). Байт-код зависит от версии интерпретатора. Если вы обновите Python, то в каталоге появятся новые файлы для новой версии, а старые станут не нужны.
Зачем всё это нужно? Чтобы не компилировать модули каждый раз. Пока исходный файл не менялся, Python берёт готовый байт-код из __pycache__. Если вы изменили helper.py, то Python заметит это (он сверяет время изменения и размер файла, которые записаны внутри .pyc) и скомпилирует модуль заново.
Важно понимать, что это ускоряет только загрузку модулей, то есть запуск программы. Сама программа от этого быстрее работать не станет, ведь байт-код всё равно выполняет виртуальная машина.
Что ещё полезно знать про __pycache__:
- Каталог можно смело удалять, Python создаст его заново.
- Если вы используете git, добавьте
__pycache__/в файл .gitignore, коммитить эти файлы не нужно. - Запретить создание .pyc можно ключом
-Bили переменной окружения:
$ python3 -B program.py
$ export PYTHONDONTWRITEBYTECODE=1
- Переместить все .pyc в отдельный каталог можно переменной
PYTHONPYCACHEPREFIX. - Скомпилировать все модули заранее (например, при сборке пакета или образа) можно так:
$ python3 -m compileall .
Другие реализации Python
Раз Python это просто язык, а интерпретатор можно написать по-разному, то разные люди сделали свои реализации. Вот самые известные:
- CPython — эталонная реализация, о которой мы говорили выше. Написана на C.
- PyPy — реализация со встроенным JIT-компилятором. Он на лету превращает часто выполняемые участки кода в машинный код. Поэтому долгоживущие программы с большим количеством вычислений на PyPy часто работают быстрее, чем на CPython. Но PyPy обычно отстаёт от CPython по поддерживаемой версии языка, и не все библиотеки на нём работают.
- GraalPy — реализация для платформы GraalVM (Java). Позволяет запускать Python и использовать его из Java-программ. Поддерживает Python 3.
- IronPython — реализация для платформы .NET. Версия 3.4 за основу берёт синтаксис Python 3.4, хотя некоторые возможности новее, например f-строки.
- Jython — реализация для JVM, компилирует код в байт-код Java. Но она так и осталась на Python 2.7, а последний релиз вышел в августе 2024 года. Для нового кода на Python 3 она не подходит.
- MicroPython — урезанная реализация для микроконтроллеров, где нет места для полноценного CPython.
Для большинства задач, в том числе для системного администрирования, достаточно обычного CPython.
Что изменилось в последних версиях
С 2022 года интерпретатор Python сильно изменился, и это стоит знать.
Python 3.11 (2022 год) заметно ускорил CPython. Виртуальная машина научилась подставлять более быстрые варианты инструкций для часто выполняемого кода.
Python 3.13 (2024 год) добавил два экспериментальных режима: JIT-компилятор и сборку без GIL.
Python 3.14 (октябрь 2025 года) сделал сборку без GIL официально поддерживаемой. А в официальных сборках для Windows и macOS появился экспериментальный JIT.
Python 3.15 (октябрь 2026 года) улучшил JIT: на Linux x86-64 он примерно на 7-8% быстрее обычного интерпретатора. Но он по-прежнему экспериментальный и по умолчанию выключен. Также в 3.15 кодировкой по умолчанию стал UTF-8.
Разберёмся, что это за зверьки.
GIL и сборка без GIL
GIL (Global Interpreter Lock, глобальная блокировка интерпретатора) это механизм в CPython, который позволяет выполнять байт-код только одному потоку в один момент времени. Поэтому несколько потоков (threading) не могут одновременно загрузить несколько ядер процессора вычислениями на Python. Для таких задач приходилось использовать несколько процессов (multiprocessing).
Сборка free-threaded («свободные потоки») работает без GIL, и потоки могут выполняться по-настоящему параллельно. В Python 3.14 она стала официально поддерживаемой, но не стала сборкой по умолчанию. Выбрано ли это решение окончательно, пока неизвестно. У такой сборки есть минусы: однопоточный код может работать чуть медленнее, а расширения на C должны быть адаптированы.
Исполняемый файл такой сборки обычно называется с буквой t, например python3.14t. Проверить, включён ли GIL, можно так (метод появился в Python 3.13):
$ python3 -c "import sys; print(sys._is_gil_enabled())"
True
Если вернулось True, то GIL работает. В сборке без GIL вы увидите False.
JIT-компилятор
JIT (Just-In-Time, «точно в срок») компилятор превращает часто выполняемые участки байт-кода в машинный код прямо во время работы программы. Так делает PyPy, а теперь такой механизм появился и в самом CPython. Пока он экспериментальный, по умолчанию выключен и в некоторых программах может даже замедлять выполнение. Поэтому в продакшене его пока лучше не включать.
Забавно, что граница между «компилируемыми» и «интерпретируемыми» языками стирается всё сильнее: исходный код превращается в байт-код, а часть байт-кода потом в машинный код.
Итоги
Подведём итоги:
- Python принято называть интерпретируемым языком, но внутри интерпретатора есть компилятор и виртуальная машина.
- Компилятор превращает код в байт-код, а виртуальная машина (PVM) его выполняет.
- Байт-код импортируемых модулей сохраняется в каталоге
__pycache__. Это ускоряет запуск программы, а не её выполнение. Сам запускаемый файл на диск не сохраняется. - Основная реализация Python называется CPython, она написана на C. Есть и другие: PyPy, GraalPy, IronPython и так далее.
- В новых версиях CPython появились экспериментальный JIT и сборка без GIL.
Ссылки
- PEP 779 — free-threaded Python официально поддерживается
- Что нового в Python 3.14
- Что нового в Python 3.15
- Модуль dis
Если понравилась статья, подпишись на мой канал в VK или Telegram .