Упаковка Python в exe (freezing) — это сборка скрипта .py, интерпретатора Python и всех его зависимостей в один исполняемый файл, который запускается на машине без установленного Python. Важно сразу развести термины: почти все, что называют «компиляцией py в exe», на деле является именно упаковкой, а не переводом кода в машинные инструкции. Ниже разберу, что происходит внутри, какие инструменты брать в 2026 году под конкретную задачу, соберу exe через PyInstaller шаг за шагом и покажу, что делать, когда файл не запускается. Код в статье прогнан, вывод под ним реальный.
Содержание
- Компиляция или упаковка: что реально происходит
- Инструменты 2026: что взять под задачу
- Сборка через PyInstaller шаг за шагом
- auto-py-to-exe: та же сборка мышкой
- Настоящая компиляция: Nuitka
- Данные и ресурсы внутри exe
- Если сборка не запускается: диагностика по симптому
- Выводы
- Где применяется и что учить дальше
- FAQ
Компиляция или упаковка: что реально происходит
Когда вы запускаете python hello.py, интерпретатор сначала переводит исходник в промежуточный байткод (файлы .pyc), а затем выполняет его на виртуальной машине CPython. Готового машинного кода под процессор здесь не появляется — байткод исполняет сам интерпретатор.
Инструменты вроде PyInstaller не меняют эту схему. Они берут ваш байткод, добавляют к нему интерпретатор и нужные библиотеки и «замораживают» все это в один файл. Такой процесс называют freezing (заморозка, упаковка), а не компиляцией. Внутри exe по-прежнему лежит байткод, который на запуске распаковывается и исполняется встроенным интерпретатором.
Цепочка получается такая: исходник .py -> байткод .pyc -> упаковка вместе с интерпретатором -> один исполняемый файл. Настоящая компиляция в машинный код — это отдельный сценарий: его закрывает Nuitka, о нем ниже.
Разница практичная. Упакованный exe весит десятки мегабайт (внутри целый интерпретатор) и работает с той же скоростью, что и обычный скрипт. Скомпилированный Nuitka файл тяжелее собрать, но он ближе к нативному коду и лучше скрывает исходник.
Инструменты 2026: что взять под задачу
Выбор зависит не от «самого нового» инструмента, а от задачи. Ориентир ниже.
| Задача | Что взять | Когда иначе |
|---|---|---|
| Быстро собрать exe из скрипта под текущую ОС | PyInstaller | нужна графическая настройка сборки |
| Настраивать сборку мышкой, без флагов в консоли | auto-py-to-exe | нужен только результат в CI/скриптом |
| Настоящая компиляция в машинный код, скорость и защита исходника | Nuitka | нужна максимально простая и быстрая сборка |
| Проект с классической установкой через setup-скрипт | cx_Freeze | достаточно одной команды PyInstaller |
| Только Windows, историческая совместимость | py2exe | переносимость на macOS/Linux (py2exe их не умеет) |
Важная оговорка: PyInstaller, auto-py-to-exe и cx_Freeze — это упаковщики (freezers), они не превращают Python в машинный код. Реальную компиляцию делает только Nuitka. Онлайн-сервисы «py to exe» я не рекомендую: вы загружаете свой код на чужой сервер, а результат непредсказуем по составу и безопасности.
Сборка через PyInstaller шаг за шагом
PyInstaller — самый ходовой вариант. Дорожная карта до готового артефакта dist/hello.exe:
- Установить:
pip install pyinstaller. - Подготовить рабочий скрипт (пример ниже).
- Собрать:
pyinstaller --onefile hello.py. - Забрать exe из появившейся папки
dist.
Возьмем минимальный, но полностью рабочий скрипт hello.py:
# hello.py - маленькое приложение, которое соберем в exe
def greet(name):
return f"Привет, {name}! Это приложение запущено из собранного файла."
if __name__ == "__main__":
print(greet("мир"))
print("2 + 2 =", 2 + 2)
При обычном запуске python hello.py он выводит:
Привет, мир! Это приложение запущено из собранного файла.
2 + 2 = 4
Теперь команда сборки. Флаг --onefile (короткий -F) складывает все в один файл:
pyinstaller --onefile hello.py
В консоли пройдет длинный лог анализа зависимостей и упаковки, который заканчивается примерно так:
... INFO: Building EXE from EXE-00.toc completed successfully.
После этого рядом появятся папки build (рабочие файлы и логи) и dist (готовый результат), а также файл hello.spec с параметрами сборки. Исполняемый файл лежит в dist: на Windows это dist\hello.exe, на macOS и Linux — файл dist/hello без расширения. Запуск dist\hello.exe выведет ровно те же две строки, что и скрипт выше.
Ключевое ограничение: кросс-компиляции здесь нет. PyInstaller собирает exe только под ту ОС, на которой запущен. Чтобы получить Windows-exe, нужен Windows (реальный, виртуальная машина или Windows-раннер в CI); собрать его из-под macOS одной командой не выйдет.
onefile или onedir
У PyInstaller два режима вывода, и выбор между ними — частый вопрос.
| Режим | Флаг | Что получается | Когда брать |
|---|---|---|---|
| Один файл | --onefile / -F |
единственный exe | удобно раздавать, но запуск чуть медленнее (распаковка во временную папку) |
| Папка | --onedir / -D |
exe плюс папка с библиотеками | быстрее стартует, проще отлаживать; по умолчанию |
Еще один полезный флаг — --noconsole (он же --windowed): он прячет черное окно консоли и нужен для программ с графическим интерфейсом. Для консольных утилит его, наоборот, не ставят, иначе вы не увидите вывод и ошибки.
auto-py-to-exe: та же сборка мышкой
auto-py-to-exe — это не отдельный компилятор, а графическая надстройка над PyInstaller. Устанавливается через pip install auto-py-to-exe, запускается одноименной командой и открывает окно, где вы выбираете скрипт, режим (onefile или onedir), наличие консоли и иконку. По кнопке «Convert .py to .exe» программа собирает те же флаги PyInstaller и вызывает его за вас. Если разобрались с PyInstaller в консоли, auto-py-to-exe не даст ничего нового, кроме удобства настройки.
Настоящая компиляция: Nuitka
Если под «компиляцией» вы имеете в виду именно перевод в машинный код, это делает Nuitka. Она транслирует ваш Python в код на C, а затем собирает его системным компилятором C в нативный исполняемый файл.
Устанавливается через pip install nuitka, для сборки нужен установленный компилятор C (на Windows Nuitka умеет сама подтянуть подходящий MinGW). Базовая команда для одного файла:
python -m nuitka --onefile hello.py
Плюсы против упаковщиков: результат обычно быстрее на вычислительной нагрузке и надежнее скрывает исходный код, потому что готового байткода внутри уже нет. Минусы: сборка дольше и требует рабочего компилятора C. Nuitka — разумный выбор, когда важны скорость или защита кода; для «просто собрать exe» PyInstaller проще.
Данные и ресурсы внутри exe
Частая проблема после сборки: программа искала рядом файл (картинку, конфиг, data.txt), а в собранном exe его «не находит». Причина в том, что в режиме --onefile PyInstaller распаковывает вложенные файлы во временную папку, путь к которой лежит в sys._MEIPASS, а не в папке со скриптом.
Универсальный помощник, который работает и при обычном запуске, и внутри собранного файла:
import sys
import os
def resource_path(rel_path):
# sys._MEIPASS есть только внутри onefile-сборки PyInstaller;
# при обычном запуске берем папку самого скрипта
base = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base, rel_path)
print("frozen:", getattr(sys, "frozen", False))
print("имя файла ресурса:", os.path.basename(resource_path("data.txt")))
Вне сборки скрипт выводит:
frozen: False
имя файла ресурса: data.txt
Флаг sys.frozen установлен только внутри собранного приложения, поэтому по нему код понимает, где именно он выполняется. Сам файл data.txt в сборку нужно явно добавить флагом --add-data, иначе внутри exe его просто не будет.
Если сборка не запускается: диагностика по симптому
- Окно мелькает и сразу закрывается. Так ведет себя консольный exe, запущенный двойным кликом: программа отработала и вышла. Запускайте из уже открытой консоли или добавьте в конце
input(), чтобы увидеть вывод. - Антивирус удаляет или блокирует exe. Частое ложное срабатывание на загрузчик PyInstaller в режиме
onefile. Помогает сборка в режиме--onedir, обновление PyInstaller до свежей версии и добавление файла в исключения. ModuleNotFoundErrorпри запуске, хотя скрипт работал. Упаковщик не нашел зависимость, которая подгружается динамически. Добавьте ее флагом--hidden-import <имя_модуля>.- exe собран под другую ОС. Windows-exe не запустится на macOS или Linux и наоборот. Собирайте под ту систему, где будете запускать.
Выводы
- Почти любая «компиляция py в exe» на деле упаковка (freezing): внутри exe лежит байткод и интерпретатор, которые распаковываются и исполняются на запуске, а не машинный код.
- PyInstaller — основной путь:
pip install pyinstaller,--onefileсобирает единственный exe в папкеdist; кросс-компиляции нет, файл собирается только под ту ОС, где запущена сборка. - auto-py-to-exe — это графическая надстройка над PyInstaller, а не отдельный компилятор: те же флаги, только мышкой.
- Настоящую компиляцию в машинный код делает только Nuitka (Python -> C -> нативный файл): быстрее на вычислениях и лучше скрывает исходник, но сборка дольше и нужен компилятор C.
- Типовые сбои решаются по симптому: ресурсы в
--onefileищут черезsys._MEIPASS, динамические зависимости добавляют флагом--hidden-import, а exe запускают на той же ОС, под которую он собран.
Где применяется и что учить дальше
Сборка в exe нужна, когда программу на Python отдают людям без установленного интерпретатора: небольшие утилиты, десктопные инструменты с графическим интерфейсом, внутренние скрипты для коллег. На практике это связка из трех навыков: писать переносимый код, разбираться в зависимостях проекта и настраивать сборку под целевую ОС.
Освойте тему на практике
Если хочется освоить Python до уровня, где упаковка и деплой — рутинная часть работы, а не квест, посмотрите специализацию Python-разработчика в Otus. Оценить формат и уровень до старта помогают бесплатные открытые уроки Otus — живые занятия с преподавателями.
FAQ
Можно ли собрать Windows-exe на macOS или Linux? Одной командой — нет. PyInstaller, cx_Freeze и Nuitka не умеют кросс-компиляцию и собирают файл только под текущую ОС. Для Windows-exe используют Windows: отдельную машину, виртуалку или Windows-раннер в CI.
Почему exe получается таким большим (десятки мегабайт)? Потому что внутрь кладется весь интерпретатор Python и подтянутые библиотеки. Уменьшить размер помогают виртуальное окружение только с нужными пакетами и утилита UPX для сжатия исполняемого файла.
Скрывает ли exe мой исходный код? У упаковщиков (PyInstaller и подобных) — слабо: внутри лежит байткод, который поддается обратному разбору. Если защита кода важна, берите Nuitka — после компиляции в машинный код восстановить исходник заметно сложнее.



