Создание исполняемого Python файла для Windows
В Windows регистрация расширения .pyz не является обязательной и кроме того, есть определенные моменты, при которых зарегистрированные расширения не распознаются «прозрачно». Самый простой пример команда subprocess.run([‘myapp’]) не найдет приложение и нужно явно указать расширение .pyz . Поэтому в Windows часто предпочтительнее из zipapp создать исполняемый файл. Это относительно просто, хотя для этого нужен компилятор языка Си.
Основной подход основан на том факте, что к zip-файлам могут добавляться произвольные данные и к файлам exe в Windows так же могут добавляться произвольные данные. Поэтому, создав подходящий модуль запуска и прикрепив файл приложения .pyz к его концу, можно получить исполняемый файл, который будет нормально работать в Windows.
Подходящий модуль запуска может быть таким:
#define Py_LIMITED_API 1 #include "Python.h" #define WIN32_LEAN_AND_MEAN #include #ifdef WINDOWS int WINAPI wWinMain( HINSTANCE hInstance, /* Обращение к текущему экземпляру */ HINSTANCE hPrevInstance, /* Обращение к предыдущему экземпляру */ LPWSTR lpCmdLine, /* Указатель на командную строку */ int nCmdShow /* Показать состояние окна */ ) #else int wmain() #endif wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*)); myargv[0] = __wargv[0]; memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *)); return Py_Main(__argc+1, myargv); >
Если определить препроцессор обработки окон WINDOWS, это сгенерирует исполняемый файл GUI, а без него — исполняемый консольный файл.
Чтобы скомпилировать исполняемый файл, можно либо просто использовать стандартные инструменты командной строки MSVC , либо воспользоваться тем, что distutils знает, как скомпилировать исходный код Python:
from distutils.ccompiler import new_compiler import distutils.sysconfig import sys import os from pathlib import Path def compile(src): src = Path(src) cc = new_compiler() exe = src.stem cc.add_include_dir(distutils.sysconfig.get_python_inc()) cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs')) # First the CLI executable objs = cc.compile([str(src)]) cc.link_executable(objs, exe) # Now the GUI executable cc.define_macro('WINDOWS') objs = cc.compile([str(src)]) cc.link_executable(objs, exe + 'w') if __name__ == "__main__": compile("zastub.c")
В результате запускается «Limited ABI», поэтому он будет работать без изменений с любой версией Python 3.x. Все, что ему нужно, это чтобы Python python3.dll был в PATH пользователя.
Для полностью автономного дистрибутива вы можете собрать файл инсталятора install.exe , в котором будут находится дистрибутив Python вместе с приложением, что будет работать на любом ПК с соответствующей архитектурой.
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Интерфейс командной строки модуля zipapp
- Функции create_archive() модуля zipapp
- Функция get_interpreter() модуля zipapp
- Тонкости распространения исполняемых приложений Python
- Автономное приложение на Python с помощью zipapp
- Создание исполняемого Python файла для Windows
Преобразование Python кода в исполняемые файлы Windows и Android

Сегодня рассмотрим способы преобразования обычного Python файла в исполняемый файл.
реклама
Исполняемый файл- это тип файла, который может быть установлен или активирован на устройстве без необходимости в дополнительном ПО или библиотеках. Преобразовав свой Python-скрипт в исполняемый файл exe/apk, вы защитите свой код от модификаций или прочтения, а также упростите работу с вашей программой.
Подготовка
Для начала я создам python скрипт для проверки его работоспособности после преобразования в исполняемый файл. Этот код рисует черный круг с помощью модуля turtle.
В исполняемый файл Windows
PyInstaller
реклама
Это один из популярных инструментов для создания исполняемых файлов из файлов Python. Он позволяет упаковать все зависимости вашего проекта в один исполняемый файл. Чтобы использовать PyInstaller, установите его с помощью команды в командной строке:
pip install pyinstaller
Теперь переходим в директорию с .py файлом
cd C:\Путь_к_папке
реклама
Наиболее часто используемые аргументы PyInstaller:
- —onefile или -F: Создает одиночный исполняемый файл, включая все зависимости.
- —onedir или -D: Создает исполняемый файл в виде набора файлов и папок, сохраняя зависимости в отдельной папке.
- —name или -n: Устанавливает имя исполняемого файла.
- —icon или -i: Устанавливает лого для исполняемого файла (должна быть в формате .ico).
- —noconsole или -w: Исполняемый файл будет запускаться без консольного окна (для скрытия консольного вывода).
- —add-data или -a: Добавляет дополнительные файлы или папки, которые должны быть включены в исполняемый файл.
- —exclude-module или -x: Исключает указанный модуль из упаковки.
- —-hidden-import или -p: Указывает модули, которые должны быть включены в упаковку, но не обнаружены автоматически.
Теперь давайте скомпилируем наш код в exe файл. Для этого прописываем команду:
pyinstaller файл.py
После завершения процесса появилось две папки: build и dist. Папка build используется программой для хранения временных данных, необходимых для сборки исполняемого файла. В папке dist хранится результат выполненной операции.
реклама
Собранный exe будет работать только в том случае, если находится в одной папке со всеми дополнительными файлами. Если его переместить или удалить доп. файлы, то он работать не будет.
Чтобы этого избежать можно использовать аргумент —onefile или -F
pyinstaller -F файл.py
PyInstaller собрал все доп. файлы в архив и теперь в папке dist находится только нужный нам exe файл. Его можно переместить, а папки build и dist удалить.
В исполняемый файл Android
Buildozer
Это инструмент, ориентированный на Linux дистрибутивы для автоматизации сборки и упаковки приложений Python для платформы Android. Если у вас Windows, то необходимо использовать WSL или другие виртуальные машины. Ваш python файл должен быть совместимым с Android. Buidozer позволяет создавать apk из файлов Python с минимальными усилиями. Для установки прописываем это в командной строке linux:
sudo apt update && sudo apt upgrade && sudo apt install -y git zip unzip openjdk-17-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev && pip install buildozer
Теперь нужно создать .spec файл в котором будет храниться вся информация о приложении. Сначала перейдите в нужную директорию в командной строке.
buildozer init
Необходимо переименовать python файл в main.py. Открываем появивщийся buildozer.spec файл и переходим к настройке. Вот некоторые из наиболее часто используемых параметров, которые можно настроить:
- title — Название исполняемого файла.
- package.name — Имя пакета вашего исполняемого файла .
- package.domain — Доменное имя вашего приложения.
- source.dir — Путь к .py файлу.
- source.include_exts — Расширения файлов, которые должны быть включены в сборку.
- version — Версия исполняемого файла.
- requirements — Зависимости файла.
Прописываем эту команду для запуска сборки apk приложения:
buildozer android debug
В теории после сборки вы получите apk приложение. Но далеко не факт, что все получится без ошибок, с первого раза и получится вообще, ведь
Как из файла Python3 создать .exe на Windows

Мы рассмотрим создание .exe с помощью библиотеки модуля py2exe. Для этого необходим Python 3.4 и ниже.
Если у вас установлена более высокая версия Python, попробуйте использовать Способ 2 (ниже)
В этом примере мы рассмотрим создание .exe на примере Python3.4.
Прежде всего на нужно создать виртуальное окружение для Python3.4. В этом примере мы назовем myenv, Вы можете выбрать любое другое имя, но не забывайте сделать соответствующие изменения.
На терминале наберите следующие команды:
>py -3.4 -m venv myenv > myenv\Scripts\activate.bat
В командной строке появится префикс myenv, а это значит, что виртуальное окружение с именем myenv загружено. Все команды Python теперь будет использовать новое виртуальное окружение.
Теперь давайте установим py2exe (https://pypi.python.org/pypi/py2exe~~HEAD=dobj) в нашем виртуальном окружении:
>pip install py2exe
И, наконец, чтобы создать единый EXE-файл, в нашем виртуальном окружении выполняем команду:
>python -m py2exe.build_exe hello.py -c --bundle-files 0
(замените hello.py на имя вашего скрипта. Если скрипт находится в другой папке, то нужно использовать полный путь к вашему сценарию, например, C:\Projects\Python\ hello.py). Это создаст папку DIST, которая содержит исполняемый файл. Для быстрого доступа к нему, наберите в терминале:
> explorer dist
Вы увидите путь к папке, где находится EXE-файл.
Примечание: При выполнении, откроется окно и исчезают так же быстро, как и появилось.
Это происходит потому, что операционная система автоматически закрывает терминал, в котором консольная программа закончена.
Для того, чтобы изменить эту ситуацию, можно добавить строчку
> input (" Нажмите для выхода . ")
в конце файла Python. Интерпретатор будет ждать ввода пользователя, а окно будет оставаться открытым, пока пользователь не нажимает клавишу ввода.
Вы можете подробно изучить использование py2exe в документации на странице модуля: https://pypi.python.org/pypi/py2exe
Выход из виртуального окружения производится командой
>deactivate
Способ 2
Через командную строку Windows устанавливаем pyinstaller:
>pip install pyinstaller
В командной строке переходим в папку, где находится файл
cd c:\.
Затем в командной строке набираем команду
pyinstaller --onefile example.py
Вместо exapmle.py используем имя файла, из которого нужно создать exe файл.
Через пару минут все готово! Скоркее всего, exe файл будет находится во созданной подпапке dist
Автономный исполняемый файл в PYTHON
И снова ночи! И снова нужна помощь, на этот раз не получается создать полностью автономный исполняемый файл приложения. Варант держать все файлы в одной папке не подходит, про него я читал, да и у самого получалсь таким образом запускать приложение на другом ПК. Я нашел ветку в англоязычной части StackOverflow, но разобраться не смог. Попробую изложить то, в чем, как мне кажется, более менее разобрался. Есть скрипт небольшой программы, все работает, все замечательно. В программе использована внешняя картинка и вот её вшить в .exe’шник не выходит. Я использовал такое руководство к действию:
Находится она в этой ветке: https://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile/63997336#63997336 Из того, что я там понял это: 1 — в скрип, встрайвается сл. код:
def resource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ try: # PyInstaller creates a temp folder and stores path in _MEIPASS base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path)
2 — нужно задействовать def resource_path в скрипте, связав с картинками:
img_dir = resource_path("img")
Уже на этом этапе я не понимаю как это сделать. В моем скрипте (прикреплю полный листинг в конце), для иконки окна используется сл. конструкция:
icon = tk.PhotoImage(file=r'H:\PYTHON\CATRi\res\CATRi.png') app.iconphoto(False, icon)
Каким образом связать это с тем что я написал выше, что бы задействовать def resource_path, не понимаю. 3 — создать и отредактировать файл .spec, тут вроде бы все понятно. 4 — скомпилировать и радоваться. С этим тоже вопросов не возникает. Прикладываю полный листинг программы:
import tkinter as tk from tkinter import ttk import sys import os def res_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ try: # PyInstaller creates a temp folder and stores path in _MEIPASS base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) # ----------------------------------------------------------------------------------- MAIN WINDOW app = tk.Tk() app.title('CATRi') icon = tk.PhotoImage(file=r'H:\PYTHON\CATRi\res\CATRi.png') app.iconphoto(False, icon) app.geometry('300x600') app.resizable(width=False, height=False) app.update_idletasks() s = app.geometry() s = s.split('+') s = s[0].split('x') width_app = int(s[0]) height_app = int(s[1]) w = app.winfo_screenwidth() h = app.winfo_screenheight() w = w // 2 h = h // 2 w = w - width_app // 2 h = h - height_app // 2 app.geometry('+<>+<>'.format(w, h)) # ----------------------------------------------------------------------------------- INTERFACE # ---------------------------------------------------------------- Patient Section labelTitle = tk.Label(text='Пациент:', fg='#eee', bg='#333') labelTitle.place(relwidth=1.0, relx=.5, rely=.02, anchor='center') patientName = tk.StringVar() patientNameLabel = tk.Label(text='ФИО:') patientNameLabel.place(x=8, y=45, anchor='w') patientName_entry = tk.Entry(textvariable=patientName) patientName_entry.place(x=45, y=45, relwidth=.8, anchor='w') patientDate = tk.StringVar() patientDateLabel = tk.Label(text='Дата рождения:') patientDateLabel.place(x=8, y=68, anchor='w') patientDate_entry = tk.Entry(textvariable=patientDate) patientDate_entry.place(x=101, y=68, relwidth=.612, anchor='w') patientSexLabel = tk.Label(text='Пол:') patientSexLabel.place(x=68, y=92, anchor='w') patientSelectSex = ttk.Combobox(app, values=['мужской', 'женский']) patientSelectSex.place(x=101, y=92, relwidth=.25, anchor='w') # ----------------------------------------------------------------------------------- PARAMETERS labelTitle = tk.Label(text='Анамнез:', fg='#eee', bg='#333') labelTitle.place(relwidth=1.0, relx=.5, rely=.206, anchor='center') # ---------------------------------------------------------------- Course Select courseLabel = tk.Label(text='1. Течение:') courseLabel.place(x=7, y=150, anchor='w') courseSelect = ttk.Combobox(app, values=['бессимптомное', 'симптомное', '']) courseSelect.place(x=11, y=177, relwidth=.40, anchor='w') courseSelect.current(2) # ---------------------------------------------------------------- Stenosis Select stenosisLabel = tk.Label(text='2. Стеноз ВСА:') stenosisLabel.place(x=162, y=150, anchor='w') stenosisSelect = ttk.Combobox(app, values=['нет', 'менее 50%', 'от 50 до 70%', 'более 70%', 'окклюзия', '']) stenosisSelect.place(x=165, y=177, relwidth=.40, anchor='w') stenosisSelect.current(5) # ---------------------------------------------------------------- Plaque Select plaqueLabel = tk.Label(text='3. Бляшка:') plaqueLabel.place(x=8, y=227, anchor='w') plaqueSelect = ttk.Combobox(app, values=['нет', 'стабильная', 'нестабильная', '']) plaqueSelect.place(x=11, y=254, relwidth=.40, anchor='w') plaqueSelect.current(3) # ---------------------------------------------------------------- Hearth Select hearthLabel = tk.Label(text='4. Очаг ишемии:') hearthLabel.place(x=162, y=227, anchor='w') hearthSelect = ttk.Combobox(app, values=['нет', 'менее 2,5 см', '2,5 см', 'более 2,5 см', '']) hearthSelect.place(x=165, y=254, relwidth=.40, anchor='w') hearthSelect.current(4) # ---------------------------------------------------------------- Transformation Select transformationLabel = '5. Геморрагическая \n трансформация:' transformationLabel = tk.Label(text=transformationLabel, justify=tk.LEFT) transformationLabel.place(x=7, y=300, anchor='w') transformationSelect = ttk.Combobox(app, values=['нет', 'есть', '']) transformationSelect.place(x=11, y=331, relwidth=.40, anchor='w') transformationSelect.current(2) # ---------------------------------------------------------------- Deficit Select deficitLabel = '6. Неврологический \n дефицит:' deficitLabel = tk.Label(text=deficitLabel, justify=tk.LEFT) deficitLabel.place(x=162, y=300, anchor='w') deficitSelect = ttk.Combobox(app, values=['нет', 'Ренкин 1-3', 'Ренкин 4-5', '']) deficitSelect.place(x=165, y=331, relwidth=.40, anchor='w') deficitSelect.current(3) # ----------------------------------------------------------------------------------- CONCLUSION labelTitle = tk.Label(text='Заключение:', fg='#eee', bg='#333') labelTitle.place(relwidth=1.0, relx=.5, rely=.68, anchor='center') # ----------------------------------------------------------------------------------- ENGINE def clearPatientValues(): patientName_entry.delete(0, tk.END) patientDate_entry.delete(0, tk.END) patientSelectSex.set('') def appAnalyse(): courseVar = courseSelect.get() stenosisVar = stenosisSelect.get() plaqueVar = plaqueSelect.get() hearthVar = hearthSelect.get() transformationVar = transformationSelect.get() deficitVar = deficitSelect.get() if courseVar == 'бессимптомное': courseVar = int('0') elif courseVar == 'симптомное': courseVar = int('2') elif courseVar == '': courseVar = str('') if stenosisVar == 'нет': stenosisVar = int('0') elif stenosisVar == 'менее 50%': stenosisVar = int("1") elif stenosisVar == 'от 50 до 70%': stenosisVar = int('5') elif stenosisVar == 'более 70%': stenosisVar = int('10') elif stenosisVar == 'окклюзия': stenosisVar = int('30') elif stenosisVar == '': stenosisVar = str('') if plaqueVar == 'нет': plaqueVar = int('0') elif plaqueVar == 'стабильная': plaqueVar = int('1') elif plaqueVar == 'нестабильная': plaqueVar = int('5') elif plaqueVar == '': plaqueVar = str('') if hearthVar == 'нет': hearthVar = int('0') elif hearthVar == 'менее 2,5 см': hearthVar = int('1') elif hearthVar == '2,5 см': hearthVar = int('2') elif hearthVar == 'более 2,5 см': hearthVar = int('50') elif hearthVar == '': hearthVar = str('') if transformationVar == 'нет': transformationVar = int('0') elif transformationVar == 'есть': transformationVar = int('50') elif transformationVar == '': transformationVar = str('') if deficitVar == 'нет': deficitVar = int('0') elif deficitVar == 'Ренкин 1-3': deficitVar = int('5') elif deficitVar == 'Ренкин 4-5': deficitVar = int('50') elif deficitVar == '': deficitVar = str('') print(courseVar, stenosisVar, plaqueVar, hearthVar, transformationVar, deficitVar) SCORE = courseVar + stenosisVar + plaqueVar + hearthVar + transformationVar + deficitVar print(SCORE) if SCORE == '': conclusion.config(text=f'Выберите значения!') elif SCORE == 0: conclusion.config( text=f'ЗАКЛЮЧЕНИЕ:\nРиск ОНМК отсутствует.\n\nРЕКОМЕНДОВАНО:\nСпециальных назначений не требуется.\n') elif 0 < SCORE = 50: conclusion.config( text=f'ЗАКЛЮЧЕНИЕ:\nОперативное лечение не показано.\n\nРЕКОМЕНДОВАНО:\nКонсультация сосудистого хирурга через 1 мес.\n') elif 25 < SCORE < 50: conclusion.config( text=f'ЗАКЛЮЧЕНИЕ:\nОперативное лечение не показано.\n\nРЕКОМЕНДОВАНО:\nУЗАС сонных артерий + консультация\nсосудистого хирурга 2 раза в год.\n') conclusion = '' conclusion = tk.Label(text=conclusion, anchor='center', height=10, width=41) conclusion.place(relx=.012, rely=.835, anchor='w') # ---------------------------------------------------------------- Clearing def clearComboboxValues(): courseSelect.set('') stenosisSelect.set('') plaqueSelect.set('') hearthSelect.set('') transformationSelect.set('') deficitSelect.set('') conclusion.config(text=f'') # ---------------------------------------------------------------- Buttons message_button = tk.Button(text='X', command=clearPatientValues) message_button.place(x=261, y=92, relheight=.035, relwidth=.08, anchor="w") message_button = tk.Button(text='Анализ', command=appAnalyse) message_button.place(x=165, y=370, relwidth=.40, anchor='w') message_button = tk.Button(text='Сброс', command=clearComboboxValues) message_button.place(x=11, y=370, relwidth=.40, anchor='w') app.mainloop()
Структура папок с программой:
H:/PYTHON/CATRi CATRi.py res/ # directory containing the image files main.spec

Изображение иконки (если потребуется): Сбственно если кто-то может, подскажите как можно реализовать автономность, по средством алгоритма, который я привел выше.