Создание исполняемых приложений из скриптов Python
Компиляция Python: обзор методов
Как скомпилировать Python программу в нативный исполняемый файл с помощью Nuitka?
Nuitka переводит Python код в C/C++ и затем компилирует его в машинный код. Это даёт высокую производительность и возможность распространения без интерпретатора.
Шаги:
- Установка Nuitka:
pip install nuitkaкомпиляция программ python (компиляция программ на python)
- Создайте простой скрипт hello.py:
print('Привет, мир!') - Запуск компиляции (для Windows с MinGW):
nuitka --standalone --mingw64 hello.py - После завершения появится папка hello.dist с исполняемым файлом hello.exe.
Типичные проблемы:
- Отсутствие компилятора C (MSVC или MinGW). Решение: установить MinGW через choco install mingw или использовать Visual Studio.
- Ошибки импорта внешних библиотек. Используйте ключ --nofollow-imports для явного включения.
- Большой размер файла. Примените --lto для оптимизации.
Цель: создание автономного приложения для пользователей без Python.
Как преобразовать Python модуль в расширение C с помощью Cython?
Cython позволяет писать код на Python с аннотациями статических типов, который затем транслируется в C и компилируется в динамическую библиотеку (.pyd/.so).
Пример:
- Создайте файл example.pyx:
def fib(int n): cdef int i, a=0, b=1 for i in range(n): a, b = b, a + b return a - Подготовьте setup.py:
from setuptools import setup from Cython.Build import cythonize setup( ext_modules = cythonize('example.pyx') ) - Соберите расширение:
python setup.py build_ext --inplace - Файл example.cp39-win_amd64.pyd появится в папке. Импортируйте его как обычный модуль.
Типичные проблемы:
- Ошибки синтаксиса Cython (использование cdef). Решение: изучить документацию.
- Несовместимость версий Python и Cython. Решение: обновить Cython до последней версии.
- Проблемы с многопоточностью. Используйте nogil для блоков без GIL.
Цель: ускорение узких мест Python кода.
Как упаковать Python скрипт в один исполняемый файл с помощью PyInstaller?
PyInstaller собирает интерпретатор, зависимости и скрипт в один бинарник. Это не компиляция в машинный код, но часто используется для распространения.
Команда создания одного .exe файла:
pyinstaller --onefile --windowed hello.py
Флаг --windowed убирает консольное окно для GUI приложений. Итоговый файл находится в папке dist.
Типичные проблемы:
- Большой размер (часто >30 МБ). Решение: используйте UPX для сжатия, --upx-dir.
- Антивирусы ложно определяют файл как угрозу. Решение: подписать код или добавить в исключения.
- Отсутствие необходимых файлов (например, изображений). Используйте --add-data для встраивания.
Цель: простое распространение приложения без установки Python.
Как скомпилировать Python скрипты в байт-код .pyc?
Стандартная компиляция в байт-код ускоряет загрузку модулей, но не защищает исходный код. Выполняется автоматически при импорте или с помощью модуля compileall.
Пример:
python -m compileall .
Создаются файлы в папке __pycache__. Для ручной компиляции одного файла:
import py_compile
py_compile.compile('my_script.py')
Типичные проблемы:
- Файлы .pyc не переносимы между версиями Python. Решение: перекомпилировать под целевую версию.
- Невозможность распространения без интерпретатора. Решение: использовать PyInstaller или Nuitka.
Цель: ускорение запуска больших проектов.
Как перенести Python код в браузер через компиляцию в JavaScript с помощью Transcrypt?
Transcrypt транслирует Python 3.9+ код в JavaScript, сохраняя структуру и позволяя работать с DOM.
Пример:
- Установка:
pip install transcrypt - Создайте hello.py:
from tkinter import * # для веба используется browser модуль # но для демонстрации просто: print('Hello from Python in browser') - Компиляция:
transcrypt hello.py - Появится файл hello.js, который можно подключить в HTML.
Типичные проблемы:
- Ограниченная поддержка стандартной библиотеки (не работает threading). Решение: использовать асинхронные паттерны.
- Проблемы с производительностью при больших вычислениях. Решение: использовать встроенные JS функции.
Цель: выполнение Python кода на клиенте без серверной части.
Расширенные примеры компиляции
Nuitka: включение внешних библиотек и оптимизация
Рассмотрим компиляцию скрипта, использующего numpy и matplotlib.
Код plot_sin.py:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title('Синусоида')
plt.show()
Команда компиляции с автономным режимом и плагином для Tkinter:
nuitka --standalone --enable-plugin=tk-inter --output-dir=./build --lto plot_sin.py
Результат:
Создана папка build/plot_sin.dist. Внутри plot_sin.exe (около 60 MB) и все необходимые библиотеки. При запуске отображается окно с графиком.
Возможная ошибка: 'ImportError: No module named 'matplotlib.backends.backend_agg''. Решение: добавить --nofollow-import-to='matplotlib' и вручную скопировать модули, или использовать --include-package=matplotlib.
Cython: ускорение рекурсивного вычисления чисел Фибоначчи
Сравнение чистой реализации Python и Cython с явными типами.
fib_py.py:
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
fib_cy.pyx:
def fib(int n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
Компиляция с помощью setup.py:
from setuptools import setup
from Cython.Build import cythonize
setup(ext_modules = cythonize('fib_cy.pyx', compiler_directives={'language_level': '3'}))
Сборка: python setup.py build_ext --inplace
Тест скорости:
import time
from fib_py import fib as fib_py
from fib_cy import fib as fib_cy
start = time.time()
print(fib_py(35))
print('Python time:', time.time() - start)
start = time.time()
print(fib_cy(35))
print('Cython time:', time.time() - start)
Результат:
9227465 Python time: 2.345 sec 9227465 Cython time: 0.045 sec
Типичная ошибка: Рекурсивный вызов в Cython может быть медленным из-за накладных расходов. Решение: использовать итеративный подход или @cython.cfunc для внутренних функций.
Transcrypt: работа с DOM элементами
Пример скрипта, меняющего содержимое HTML страницы.
Код dom_demo.py:
# Компиляция: transcrypt -b -n dom_demo.py
from browser import document, window
def change_text():
document['output'].text = 'Новый текст из Python!'
window.onload = lambda: document['mybutton'].bind('click', change_text)
Соответствующий HTML:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="__target__/dom_demo.js"></script>
</head>
<body>
<button id="mybutton">Нажми меня</button>
<div id="output">Исходный текст</div>
</body>
</html>
Результат: при нажатии на кнопку текст в div заменяется.
Ошибка: 'browser' модуль не найден. Решение: убедиться, что Transcrypt установлен и компиляция выполняется с ключом -b (читать документацию).
PyInstaller: добавление ресурсов и иконки
Упаковка приложения с файлом данных и настройкой иконки.
Структура проекта:
my_app/
├── main.py
├── data.txt
└── icon.ico
Код main.py:
import sys
import os
def resource_path(relative_path):
"""Получить абсолютный путь к ресурсу (для собранного приложения)"""
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath('.'), relative_path)
with open(resource_path('data.txt'), 'r') as f:
print(f.read())
Команда сборки:
pyinstaller --onefile --add-data 'data.txt;.' --icon=icon.ico main.py
Результат: один файл dist/main.exe с встроенным data.txt и иконкой.
Ошибка: 'FileNotFoundError: data.txt' при запуске из собранного exe. Решение: проверить путь с sys._MEIPASS и использовать --add-data корректно (разделитель ';' на Windows, ':' на Linux).