Сборка Python проекта в один исполняемый файл: практические методы
Общие принципы создания исполняемого файла из Python скрипта
Преобразование Python кода в самостоятельный исполняемый файл (EXE) позволяет запускать приложение на компьютерах без установленного интерпретатора Python. Это востребовано при распространении утилит, игр или инструментов для пользователей, не знакомых с программированием. Рассмотрим несколько подходов, каждый из которых имеет свои особенности.
Как собрать Python скрипт в один файл EXE с помощью PyInstaller?
PyInstaller - самый популярный инструмент для этой задачи. Он анализирует зависимости, упаковывает их вместе с вашим кодом и создаёт самодостаточный EXE файл.
pip install pyinstallerкомпиляция кода python (компиляция кода python)
Базовая команда для сборки:
pyinstaller --onefile my_script.pyPython compile py (компиляция python кода)
После выполнения в папке dist появится файл my_script.exe.
Типичная ошибка:
Если скрипт использует неявно импортируемые модули (например, через importlib), PyInstaller может их пропустить. Решение - указать их явно:
pyinstaller --onefile --hidden-import=my_missing_module my_script.pyPython to c to exe (конвертация python в c и в exe)
Для скрытия консольного окна (GUI приложения) требуется флаг --noconsole:
pyinstaller --onefile --noconsole my_app.pyДобавление иконки:
pyinstaller --onefile --icon=logo.ico my_script.pyКак создать EXE с помощью cx_Freeze?
cx_Freeze - ещё один проверенный инструмент. Он требует создания файла setup.py с описанием проекта.
# setup.py
from cx_Freeze import setup, Executable
setup(
name="MyApp",
version="1.0",
description="Example app",
executables=[Executable("my_script.py", base="Win32GUI")]
)Сборка выполняется командой:
python setup.py buildИтоговые файлы появятся в папке build. Для создания одного EXE без библиотек рядом - потребуется дополнительная настройка (вручную или через опцию includes).
Возможная проблема:
Работа с внешними DLL (например, tkinter) может потребовать указания путей вручную.
Как применить Nuitka для компиляции Python в нативный код и получить EXE?
Nuitka транслирует Python код в C++, затем компилирует его с помощью компилятора C (например, MinGW или Visual Studio). Результат - бинарник, часто работающий быстрее оригинала.
pip install nuitka
nuitka --mingw64 --onefile my_script.pyФлаг --onefile создаёт один EXE. Если нужен запуск без консоли - добавьте --windows-disable-console.
Ошибка компиляции:
Nuitka требует установленный компилятор C. В Windows удобно использовать mingw-w64. При отсутствии появится сообщение об ошибке: "gcc not found".
Как преобразовать Python скрипт в EXE используя py2exe?
py2exe - старый, но иногда полезный инструмент. Работает только с Python 3.4-3.8 (для старых версий). Требуется setup.py.
# setup.py (py2exe)
from distutils.core import setup
import py2exe
setup(
console=["my_script.py"],
options={
"py2exe": {
"bundle_files": 1, # 1 - все в один EXE
"compressed": True
}
},
zipfile=None
)Запуск:
python setup.py py2exeЕсть ограничения по поддержке современных библиотек и версий Python.
Проблема:
py2exe не поддерживает Python выше 3.8. Для новых проектов лучше использовать PyInstaller или Nuitka.
Как создать EXE без кода с помощью GUI утилиты auto-py-to-exe?
auto-py-to-exe - надстройка над PyInstaller с веб-интерфейсом. Установка и запуск:
pip install auto-py-to-exe
auto-py-to-exeОткроется браузер, где можно выбрать скрипт, настроить опции (onefile, иконка, скрыть консоль) и запустить сборку одной кнопкой. Подходит для новичков.
Возможная ошибка:
Путь к скрипту не должен содержать кириллицу - это может вызвать проблемы при анализе зависимостей.
Как получить самодостаточный бинарник с PyOxidizer?
PyOxidizer создаёт исполняемый файл, встроив Python интерпретатор и все библиотеки внутрь. Требуется конфигурационный файл pyoxidizer.bzl.
# pyoxidizer.bzl (фрагмент)
def make_exe():
return dist.default_binary_dist()
register_target("exe", make_exe)
Сборка:
pyoxidizer buildИнструмент поддерживает Python 3.7+. Он создаёт очень компактные бинарники, но требует изучения своего синтаксиса. Подходит для проектов с жёсткими требованиями к размеру.
Трудность:
PyOxidizer может не поддерживать все библиотеки Python, особенно с динамической загрузкой (C extensions).
Расширенные примеры и результаты
Пример 1: PyInstaller с включением дополнительных данных (файлы конфигурации, изображения)
# tree.py
import sys
import os
from pathlib import Path
def resource_path(relative_path):
"""Получить путь к файлу, учитывая упаковку PyInstaller."""
if getattr(sys, 'frozen', False):
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
# Использование
config_path = resource_path('config.ini')
with open(config_path) as f:
print(f.read())
# Команда сборки с добавлением папки data
pyinstaller --onefile --add-data "data;data" tree.py
Результат: после запуска tree.exe он корректно находит config.ini внутри упакованного архива.
# Вывод (пример содержимого config.ini) [APP] version = 2.1 mode = production
Возможная ошибка при пропуске --add-data:
Без флага файл data/config.ini не будет скопирован в EXE, и приложение упадёт с ошибкой FileNotFoundError.
Пример 2: Nuitka с оптимизацией и замером производительности
# test_speed.py
import time
def heavy_function():
total = 0
for i in range(10_000_000):
total += i * i
return total
start = time.perf_counter()
result = heavy_function()
end = time.perf_counter()
print(f"Result: {result}")
print(f"Time: {end - start:.3f} sec")
# Команда компиляции
nuitka --mingw64 --onefile --lto=yes test_speed.py
# Результат (среднее время): Python interpreter: ~2.1 sec Nuitka compiled EXE: ~1.3 sec (ускорение ~40%)
Опция --lto=yes включает Link Time Optimization для лучшей производительности.
Пример 3: cx_Freeze с указанием включения модулей для работы с OpenCV (cv2)
# setup_opencv.py
from cx_Freeze import setup, Executable
build_exe_options = {
"packages": ["cv2", "numpy"],
"excludes": ["tkinter", "PyQt5"] # исключить ненужное
}
setup(
name="CVApp",
version="1.0",
options={"build_exe": build_exe_options},
executables=[Executable("image_processor.py")]
)
Сборка: python setup_opencv.py build
Пример 4: py2exe для старого скрипта на Python 3.6
# legacy_setup.py
from distutils.core import setup
import py2exe
import sys
# Если нет консольного окна
sys.argv.append('py2exe')
setup(
options = {
"py2exe": {
"bundle_files": 1,
"compressed": True,
"includes": ["json", "os"]
}
},
console=["legacy_script.py"],
zipfile = None,
)
Запуск: python legacy_setup.py
# Успешная сборка: в папке dist появится legacy_script.exe размером ~15 MB
Пример 5: auto-py-to-exe с нестандартным портом и автоматическим открытием
# Запуск с изменённым портом (по умолчанию 8080)
auto-py-to-exe --port 9090После открытия браузера выберите скрипт, укажите параметры и нажмите "Convert .py to .exe". Для консольных приложений отметьте "Console Based".
Пример 6: PyOxidizer с явным указанием зависимостей (для проекта с requests)
# pyoxidizer.bzl (полный файл)
def make_exe():
dist = default_python_distribution()
policy = dist.make_python_packaging_policy()
policy.allow_embedding = True
exe = dist.to_python_executable(
name="myapp",
packaging_policy=policy,
)
exe.add_python_resources(exe.pip_install(["requests"]))
exe.add_python_resources(exe.read_package_root(
path="src",
packages=["myapp"],
))
return exe
register_target("exe", make_exe, default=True)
Сборка: pyoxidizer build --release
# Результат: бинарник ~10 MB (существенно меньше, чем у PyInstaller)
Все примеры демонстрируют практические приёмы, которые помогут избежать типовых ошибок и адаптировать сборку под конкретный проект.