Как да използвам PyInstaller за създаване на изпълними файлове на Python

Python, мощен и гъвкав, какъвто е, му липсват няколко ключови възможности. Първо, Python не предоставя собствен механизъм за компилиране на програма на Python в самостоятелен изпълним пакет.

За да бъдем честни, оригиналният случай на използване на Python никога не е изисквал самостоятелни пакети. Програмите на Python като цяло се изпълняват на място в системи, в които живее копие на интерпретатора на Python. Но нарастващата популярност на Python създаде по-голямо търсене за стартиране на приложения на Python в системи без инсталирано изпълнение на Python.

Няколко трети страни са проектирали решения за внедряване на самостоятелни приложения на Python. Най-популярното решение и най-зрелото решение е PyInstaller. PyInstaller не прави процеса на пакетиране на приложение на Python напълно безболезнено, но там отива много.

В тази статия ще разгледаме основите на използването на PyInstaller, включително как работи PyInstaller, как да използваме PyInstaller за създаване на самостоятелен изпълним файл на Python, как да настроим фино изпълнимите изпълними програми на Python и как да избегнем някои от често срещаните подводни камъни с използване на PyInstaller.

Създаване на пакет PyInstaller

PyInstaller е пакет на Python, инсталиран с pip( pip install pyinstaller). PyInstaller може да бъде инсталиран във вашата инсталация на Python по подразбиране, но най-добре е да създадете виртуална среда за проекта, който искате да опаковате, и да инсталирате там PyInstaller.

PyInstaller работи, като чете вашата програма Python, анализира всички импорти, които прави, и обединява копия от тези импорти с вашата програма. PyInstaller чете във вашата програма от нейната входна точка. Например, ако входната точка на вашата програма е myapp.py, бихте изпълнили pyinstaller myapp.pyда извършите анализа. PyInstaller може да открива и автоматично пакетира много често срещани пакети на Python, като NumPy, но в някои случаи може да се наложи да предоставите подсказки. (Повече за това по-късно.)

След анализ на вашия код и откриване на всички библиотеки и модули, които той използва, PyInstaller след това генерира „файл със спецификации“. Скрипт на Python с разширението .spec, този файл включва подробности за това как вашето приложение на Python трябва да бъде опаковано. Първият път, когато стартирате PyInstaller във вашето приложение, PyInstaller ще генерира спецификационен файл от нулата и ще го запълни с някои нормални настройки по подразбиране. Не изхвърляйте този файл; това е ключът към усъвършенстването на внедряването на PyInstaller!

И накрая, PyInstaller се опитва да създаде изпълним файл от приложението, в комплект с всичките му зависимости. Когато приключи, в dist директорията на проекта ще се появи подпапка с име (по подразбиране; можете да посочите друго име). Това от своя страна съдържа директория, която е вашето пакетно приложение - има .exeфайл за стартиране, заедно с всички необходими библиотеки и други допълнителни файлове.

Всичко, което трябва да направите, за да разпространявате програмата си, е да пакетирате тази директория като .zipфайл или някакъв друг пакет. Обикновено пакетът трябва да бъде извлечен в директория, където потребителят има разрешения за запис, за да стартира.

Тестване на пакет PyInstaller

Има шанс първият ви опит да използвате PyInstaller за пакетиране на приложение да не бъде напълно успешен.

За да проверите дали вашият пакет PyInstaller работи, отидете до директорията, съдържаща свързания изпълним файл, и стартирайте .exeфайла там от командния ред. Ако не успее да се стартира, грешките, които ще видите отпечатани в командния ред, трябва да предоставят намек за това какво не е наред.

Най-честата причина, поради която пакетът PyInstaller се проваля, е, че PyInstaller не успя да обедини необходимия файл. Такива липсващи файлове попадат в няколко категории:

  • Скрит или липсващ импорт : Понякога PyInstaller не може да открие импортирането на пакет или библиотека, обикновено защото се импортира динамично. Пакетът или библиотеката ще трябва да бъдат посочени ръчно.
  • Липсващи самостоятелни файлове : Ако програмата зависи от външни файлове с данни, които трябва да се свържат с програмата, PyInstaller няма как да знае. Ще трябва ръчно да включите файловете.
  • Липсващи двоични файлове : Тук отново, ако вашата програма зависи от външен двоичен файл като .DLL, който PyInstaller не може да открие, ще трябва да го включите ръчно.

Добрата новина е, че PyInstaller предоставя лесен начин за справяне с горните проблеми. Най- .specфайл, създаден от PyInstaller включва области можем да попълнят да предоставят детайли, които PyInstaller пропуснали.

Отворете .specфайла в текстов редактор и потърсете дефиницията на Analysisобекта. Няколко от параметрите, предадени на, Analysisса празни списъци, но те могат да бъдат редактирани, за да посочат липсващите подробности:

  • hiddenimportsза скрити или липсващи импорти : Добавете към този списък един или повече низове с имената на библиотеките, които искате да бъдат включени в приложението ви. Ако искате да добавите pandasи bokeh, например, бихте посочили това като  ['pandas','bokeh']. Имайте предвид, че въпросните библиотеки трябва да бъдат инсталирани в същия екземпляр на Python, където използвате PyInstaller.
  • datasза липсващи самостоятелни файлове : Добавете тук една или повече спецификации за файлове в дървото на проекта, които искате да включите към проекта си. Всеки файл трябва да бъде предаден като кортеж, указващ относителния път към файла в директорията на вашия проект и относителния път в директорията за разпространение, където искате да поставите файла. Например, ако сте имали файл ./models/mainmodel.dat, който искате да включите в приложението си и искате да го поставите в съответстващ поддиректория в директорията си за разпространение, бихте използвали ('./models/mainmodel.dat','./models')като един запис в hiddenimportsсписъка. Имайте предвид, че можете да използвате globзаместващи символи -style, за да посочите повече от един файл.
  • binariesза липсващите самостоятелни двоични файлове : Както при datas, можете да използвате, за binariesда предадете списък с кортежи, които указват местоположенията на двоични файлове в дървото на проекта и техните дестинации в директорията за разпространение. Отново можете да използвате globзаместващи символи в стил.

Имайте предвид, че всеки от предадените списъци Analysisможе да бъде програмно генериран по-рано във .specфайла. В края на краищата .specфайлът е само скрипт на Python с друго име.

След като направите промени във .specфайла, рестартирайте PyInstaller, за да възстановите пакета. Отсега нататък не забравяйте да предадете модифицирания .specфайл като параметър (напр pyinstaller myapp.spec.). Тествайте изпълнимия файл както преди. Ако нещо все още е счупено, можете да редактирате .specфайла отново и да повторите процеса, докато всичко работи.

И накрая, когато сте доволни, че всичко работи по предназначение, може да искате да редактирате  .specфайла, за да предотвратите пакетираното приложение да показва прозорец на командния ред при стартиране. В EXEнастройките на обекта във .specфайла задайте  console=False. Потискането на конзолата е полезно, ако приложението ви има графичен интерфейс и не искате фалшив прозорец на командния ред да заблуждава потребителите. Разбира се, не променяйте тази настройка, ако приложението ви изисква команден ред.

Прецизиране на пакет PyInstaller

След като опаковате приложението си с PyInstaller и стартирате правилно, следващото нещо, което вероятно ще искате да направите, е да го намалите малко. Пакетите PyInstaller не са известни с това, че са елегантни.

Тъй като Python е динамичен език, е трудно да се предскаже какво точно ще е необходимо по време на изпълнение от дадена програма. Поради тази причина, когато PyInstaller открие импортиране на пакет, той включва всичко в този пакет, независимо дали той действително се използва по време на изпълнение от вашата програма. 

Ето добрите новини. PyInstaller включва механизъм за селективно изключване на цели пакети или отделни пространства от имена в пакетите. Да кажем например, че вашата програма импортира пакет foo, който включва foo.barи foo.bip. Ако знаете със сигурност, че вашата програма използва само логика foo.bar, можете безопасно да изключите foo.bip и спестите малко място.

За да направите това, използвате excludesпараметъра, предаден на Analysisобекта във .specфайла. Можете да предадете списък с имена - модули от най-високо ниво или пространства от точки с точки, за да изключите от вашия пакет. Например, за да изключите foo.bip, просто бихте посочили  ['foo.bip'].

Едно често изключение, което можете да направите, е tkinterбиблиотеката на Python за създаване на прости графични потребителски интерфейси на различни платформи. По подразбиране  tkinterи всички негови файлове за поддръжка са опаковани с проект PyInstaller. Ако не използвате tkinterвъв вашия проект, можете да го изключите, като добавите 'tkinter'към excludesсписъка. Пропускането tkinterще намали размера на пакета с около 7 MB.

Друго често срещано изключение са тестовите пакети. Ако пакет, който вашата програма импортира, има тестов пакет, тестовият пакет може да бъде включен в пакета ви PyInstaller. Освен ако действително не стартирате тестовия пакет във вашата внедрена програма, можете безопасно да го изключите.

Имайте предвид, че пакетите, създадени с помощта на изключения, трябва да бъдат добре тествани преди да бъдат използвани. Ако в крайна сметка изключите функционалността, която се използва в някой бъдещ сценарий, който не сте очаквали, приложението ви ще се счупи.

Съвети за PyInstaller

  • Изградете своя пакет PyInstaller на операционната система, на която планирате да се внедри.  PyInstaller не поддържа компилация на различни платформи. Ако трябва да разположите самостоятелното си приложение Python на MacOS, Linux и Windows системи, тогава ще трябва да инсталирате PyInstaller и да изградите отделни версии на приложението на всяка от тези операционни системи. 
  • Създавайте своя пакет PyInstaller, докато разработвате приложението си.  Веднага след като разберете, че ще внедрите проекта си с PyInstaller, изградете своя .specфайл и започнете да усъвършенствате пакета PyInstaller паралелно с разработването на вашето приложение. По този начин можете да добавяте изключения или включвания по време на движение и да тествате начина, по който новите функции се разполагат с приложението, докато ги пишете.
  • Не използвайте режима на PyInstaller  --onefile.  PyInstaller включва превключвател на команден ред --onefile, който пакетира цялото ви приложение в един саморазпакващ се изпълним файл. Това звучи като чудесна идея - трябва да доставите само един файл! - но има някои клопки. Всеки път, когато стартирате приложението, първо трябва да разопакова всички файлове в изпълнимия файл във временна директория. Ако приложението е голямо (например 200MB), разопаковането може да означава забавяне от няколко секунди. Вместо това използвайте режима по подразбиране с една директория и просто опаковайте всичко като .zipфайл.
  • Създайте инсталатор за вашето приложение PyInstaller.  Ако искате някакъв начин да внедрите приложението си, различен от .zip файл, помислете дали да не използвате помощна програма за инсталиране като отворения код Nullsoft Scriptable Install System. Той добавя много малко режийни разходи към размера на резултата и ви позволява да конфигурирате много аспекти на инсталационния процес, като например създаване на преки пътища към вашия изпълним файл.
  • Не очаквайте ускорения.  PyInstaller е система за  опаковане , а не  компилатор  или  оптимизатор . Кодът, пакетиран с PyInstaller, не работи по-бързо, отколкото би бил, когато се изпълнява в оригиналната система. Ако искате да ускорите кода на Python, използвайте C-ускорена библиотека, подходяща за задачата, или проект като Cython.

Как да направите повече с Python

  • Урок за Cython: Как да ускорим Python
  • Как да инсталирате Python по интелигентен начин
  • По-добро управление на проекти на Python с поезия
  • Virtualenv и venv: Обяснени са виртуалните среди на Python
  • Python virtualenv и venv правят и не
  • Обяснение на нишките на Python и подпроцесите
  • Как да използвам Python дебъгер
  • Как да използвам timeit за профилиране на Python код
  • Как да използвам cProfile за профилиране на Python код
  • Започнете с async в Python
  • Как да използвам asyncio в Python
  • Как да конвертирате Python в JavaScript (и обратно)