Jak używać PyInstaller do tworzenia plików wykonywalnych Pythona

Python, mimo że jest potężny i wszechstronny, nie ma kilku kluczowych funkcji po wyjęciu z pudełka. Po pierwsze, Python nie zapewnia natywnego mechanizmu kompilowania programu w języku Python do samodzielnego pakietu wykonywalnego.

Aby być uczciwym, oryginalny przypadek użycia Pythona nigdy nie wymagał samodzielnych pakietów. Programy w języku Python były generalnie uruchamiane na miejscu w systemach, w których mieszkała kopia interpretera języka Python. Jednak rosnąca popularność języka Python stworzyła większe zapotrzebowanie na uruchamianie aplikacji w języku Python w systemach bez zainstalowanego środowiska wykonawczego Python.

Kilka firm zewnętrznych opracowało rozwiązania do wdrażania samodzielnych aplikacji w języku Python. Najpopularniejszym i najbardziej dojrzałym rozwiązaniem z tej grupy jest PyInstaller. PyInstaller nie sprawia, że ​​proces pakowania aplikacji w języku Python przebiega całkowicie bezboleśnie, ale zajmuje to długą drogę.

W tym artykule omówimy podstawy korzystania z PyInstaller, w tym sposób działania PyInstaller, jak używać PyInstaller do tworzenia samodzielnego pliku wykonywalnego Pythona, jak dostroić pliki wykonywalne Pythona, które tworzysz i jak uniknąć niektórych typowych pułapek przy użyciu PyInstaller.

Tworzenie pakietu PyInstaller

PyInstaller to pakiet Pythona, instalowany za pomocą pip( pip install pyinstaller). PyInstaller można zainstalować w domyślnej instalacji Pythona, ale najlepiej jest utworzyć środowisko wirtualne dla projektu, który chcesz spakować, i zainstalować tam PyInstaller.

PyInstaller działa, czytając program w Pythonie, analizując wszystkie importowane przez niego importy i łącząc kopie tych importów z programem. PyInstaller czyta w twoim programie od punktu wejścia. Na przykład, jeśli punktem wejścia programu jest myapp.py, uruchomisz pyinstaller myapp.pyanalizę. PyInstaller może wykryć i automatycznie spakować wiele popularnych pakietów Pythona, takich jak NumPy, ale w niektórych przypadkach może być konieczne podanie wskazówek. (Więcej na ten temat później.)

Po przeanalizowaniu kodu i odkryciu wszystkich bibliotek i modułów, z których korzysta, PyInstaller generuje następnie „plik specyfikacji”. Skrypt w języku Python z rozszerzeniem .spec, ten plik zawiera szczegółowe informacje o tym, jak należy spakować aplikację w języku Python. Gdy po raz pierwszy uruchomisz PyInstaller w swojej aplikacji, PyInstaller wygeneruje plik specyfikacji od podstaw i zapełni go rozsądnymi wartościami domyślnymi. Nie odrzucaj tego pliku; to klucz do udoskonalenia wdrożenia PyInstaller!

Na koniec PyInstaller próbuje utworzyć plik wykonywalny z aplikacji, w pakiecie ze wszystkimi jego zależnościami. Po zakończeniu podfolder o nazwie dist (domyślnie; możesz określić inną nazwę) pojawi się w katalogu projektu. To z kolei zawiera katalog, który jest dołączoną aplikacją - zawiera .exeplik do uruchomienia wraz ze wszystkimi bibliotekami i innymi wymaganymi plikami uzupełniającymi.

Wszystko, co musisz zrobić, aby rozpowszechnić swój program, to spakować ten katalog jako .zipplik lub inny pakiet. Pakiet będzie zazwyczaj musiał zostać rozpakowany w katalogu, w którym użytkownik ma uprawnienia do zapisu, aby mógł zostać uruchomiony.

Testowanie pakietu PyInstaller

Istnieje spora szansa, że ​​pierwsza próba użycia PyInstaller do spakowania aplikacji nie zakończy się pełnym sukcesem.

Aby sprawdzić, czy Twój pakiet PyInstaller działa, przejdź do katalogu zawierającego dołączony plik wykonywalny i uruchom .exetam plik z wiersza poleceń. Jeśli to się nie powiedzie, błędy, które zobaczysz w wierszu poleceń, powinny stanowić wskazówkę, co jest nie tak.

Najczęstszą przyczyną niepowodzenia pakietu PyInstaller jest to, że PyInstaller nie mógł spakować wymaganego pliku. Takie brakujące pliki można podzielić na kilka kategorii:

  • Ukryte lub brakujące importy : Czasami PyInstaller nie może wykryć importu pakietu lub biblioteki, zwykle dlatego, że jest importowany dynamicznie. Pakiet lub bibliotekę należy określić ręcznie.
  • Brakujące pliki samodzielne : Jeśli program jest zależny od zewnętrznych plików danych, które muszą być dołączone do programu, PyInstaller nie może się tego dowiedzieć. Musisz ręcznie dołączyć pliki.
  • Brakujące pliki binarne : Tutaj ponownie, jeśli twój program zależy od zewnętrznego pliku binarnego, takiego jak .DLL, którego PyInstaller nie może wykryć, musisz go ręcznie dołączyć.

Dobra wiadomość jest taka, że ​​PyInstaller zapewnia łatwy sposób radzenia sobie z powyższymi problemami. .specPlik stworzony przez PyInstaller zawiera pola możemy wypełnić w celu zapewnienia, że dane PyInstaller nieodebranych.

Otwórz .specplik w edytorze tekstu i poszukaj definicji Analysisobiektu. Kilka parametrów przekazanych do Analysisto puste listy, ale można je edytować, aby określić brakujące szczegóły:

  • hiddenimportsw przypadku ukrytych lub brakujących importów : dodaj do tej listy co najmniej jeden ciąg z nazwami bibliotek, które chcesz dołączyć do aplikacji. Jeśli chcesz dodać pandasi bokeh, na przykład, określisz to jako  ['pandas','bokeh']. Zauważ, że odnośne biblioteki muszą być zainstalowane w tej samej instancji Pythona, w której używasz PyInstaller.
  • datasw przypadku brakujących samodzielnych plików : dodaj tutaj jedną lub więcej specyfikacji plików w drzewie projektu, które chcesz dołączyć do projektu. Każdy plik musi być przekazany jako krotka wskazująca ścieżkę względną do pliku w katalogu projektu oraz ścieżkę względną w katalogu dystrybucyjnym, w którym chcesz umieścić plik. Na przykład, jeśli masz plik, ./models/mainmodel.datktóry chcesz dołączyć do swojej aplikacji i chcesz umieścić go w odpowiednim podkatalogu w katalogu dystrybucyjnym, użyjesz go ('./models/mainmodel.dat','./models')jako jednego wpisu na hiddenimportsliście. Zauważ, że możesz użyć globsymboli wieloznacznych w stylu -w celu określenia więcej niż jednego pliku.
  • binariesw przypadku brakujących samodzielnych plików binarnych : Podobnie jak w przypadku datas, możesz użyć binariesdo przekazania listy krotek, które określają położenie plików binarnych w drzewie projektu i ich miejsca docelowe w katalogu dystrybucyjnym. Ponownie możesz użyć globsymboli wieloznacznych w stylu-.

Należy pamiętać, że każda z przekazanych list Analysismoże zostać wygenerowana programowo wcześniej w .specpliku. W końcu .specplik jest po prostu skryptem Pythona pod inną nazwą.

Po wprowadzeniu zmian w .specpliku uruchom ponownie PyInstaller, aby odbudować pakiet. Jednak od teraz pamiętaj o przekazaniu zmodyfikowanego .specpliku jako parametru (np pyinstaller myapp.spec.). Przetestuj plik wykonywalny jak poprzednio. Jeśli coś jest nadal zepsute, możesz ponownie edytować .specplik i powtarzać proces, aż wszystko będzie działać.

Wreszcie, gdy upewnisz się, że wszystko działa zgodnie z przeznaczeniem, możesz edytować  .specplik, aby uniemożliwić spakowanej aplikacji wyświetlanie okna wiersza polecenia po uruchomieniu. W EXEustawieniach obiektu w .specpliku ustaw  console=False. Wyłączenie konsoli jest przydatne, jeśli Twoja aplikacja ma GUI i nie chcesz, aby fałszywe okno wiersza poleceń prowadziło użytkowników na manowce. Oczywiście nie zmieniaj tego ustawienia, jeśli Twoja aplikacja wymaga wiersza poleceń.

Udoskonalanie pakietu PyInstaller

Po spakowaniu aplikacji z PyInstaller i poprawnym uruchomieniu, następną rzeczą, którą prawdopodobnie zechcesz zrobić, jest trochę odchudzanie. Pakiety PyInstaller nie są znane z tego, że są smukłe.

Ponieważ Python jest językiem dynamicznym, trudno jest przewidzieć, co będzie potrzebne w czasie wykonywania przez dany program. Z tego powodu, gdy PyInstaller wykryje import pakietu, zawiera wszystko w tym pakiecie, niezależnie od tego, czy jest faktycznie używany w czasie wykonywania przez program. 

Oto dobra wiadomość. PyInstaller zawiera mechanizm do selektywnego wykluczania całych pakietów lub pojedynczych przestrzeni nazw w pakietach. Na przykład, powiedzmy, że twój program importuje pakiet foo, który zawiera foo.bari foo.bip. Jeśli wiesz na pewno, że Twój program używa tylko logiki foo.bar, możesz bezpiecznie wykluczyć foo.bip i zaoszczędzić trochę miejsca.

Aby to zrobić, użyj excludesparametru przekazanego do Analysisobiektu w .specpliku. Możesz przekazać listę nazw - moduły najwyższego poziomu lub przestrzenie nazw z kropkami - aby wykluczyć z pakietu. Na przykład, aby wykluczyć foo.bip, wystarczy określić  ['foo.bip'].

Jednym z typowych wyjątków, które można wprowadzić, jest tkinterbiblioteka Pythona do tworzenia prostych, międzyplatformowych, graficznych interfejsów użytkownika. Domyślnie  tkinterwszystkie jego pliki pomocnicze są spakowane w projekcie PyInstaller. Jeśli nie używasz tkinterw swoim projekcie, możesz go wykluczyć, dodając 'tkinter'do excludeslisty. Pominięcie tkinterzmniejszy rozmiar pakietu o około 7 MB.

Innym częstym wykluczeniem są zestawy testów. Jeśli pakiet zaimportowany przez program zawiera zestaw testów, może on zostać dołączony do pakietu PyInstaller. Jeśli faktycznie nie uruchomisz zestawu testów we wdrożonym programie, możesz go bezpiecznie wykluczyć.

Pamiętaj, że pakiety utworzone za pomocą wykluczeń powinny zostać dokładnie przetestowane przed użyciem. Jeśli w końcu wykluczysz funkcje, które są używane w przyszłym scenariuszu, którego nie przewidziałeś, Twoja aplikacja się zepsuje.

Wskazówki dotyczące PyInstaller

  • Zbuduj pakiet PyInstaller w systemie operacyjnym, na którym planujesz wdrożyć.  PyInstaller nie obsługuje kompilacji międzyplatformowych. Jeśli chcesz wdrożyć samodzielną aplikację w języku Python w systemach MacOS, Linux i Windows, musisz zainstalować PyInstaller i utworzyć osobne wersje aplikacji na każdym z tych systemów operacyjnych. 
  • Zbuduj swój pakiet PyInstaller podczas tworzenia aplikacji.  Gdy tylko dowiesz się, że będziesz wdrażać swój projekt za pomocą PyInstaller, skompiluj .specplik i zacznij udoskonalać pakiet PyInstaller równolegle z tworzeniem aplikacji. W ten sposób możesz dodawać wykluczenia lub inkluzje na bieżąco i testować sposób wdrażania nowych funkcji w aplikacji w trakcie ich pisania.
  • Nie używaj --onefiletrybu PyInstaller  .  PyInstaller zawiera przełącznik wiersza poleceń --onefile, który pakuje całą aplikację w jeden samorozpakowujący się plik wykonywalny. Brzmi jak świetny pomysł - wystarczy dostarczyć jeden plik! - ale ma pewne pułapki. Za każdym razem, gdy uruchamiasz aplikację, należy najpierw rozpakować wszystkie pliki w pliku wykonywalnym do katalogu tymczasowego. Jeśli aplikacja jest duża (na przykład 200 MB), rozpakowanie może oznaczać kilkusekundowe opóźnienie. Zamiast tego użyj domyślnego trybu pojedynczego katalogu i po prostu spakuj wszystko jako .zipplik.
  • Utwórz instalator dla swojej aplikacji PyInstaller.  Jeśli chcesz wdrożyć swoją aplikację w inny sposób niż plik .zip, rozważ użycie narzędzia instalacyjnego, takiego jak system instalacji skryptowej Nullsoft typu open source. Dodaje bardzo niewiele narzutów do rozmiaru elementu dostarczanego i umożliwia skonfigurowanie wielu aspektów procesu instalacji, takich jak tworzenie skrótów do pliku wykonywalnego.
  • Nie oczekuj przyspieszenia.  PyInstaller to  system pakowania , a nie  kompilator  ani  optymalizator . Kod spakowany z PyInstaller nie działa szybciej niż w przypadku uruchomienia w oryginalnym systemie. Jeśli chcesz przyspieszyć kod w Pythonie, użyj biblioteki z akceleracją C, dostosowanej do zadania lub projektu takiego jak Cython.

Jak zrobić więcej w Pythonie

  • Samouczek Cythona: Jak przyspieszyć Pythona
  • Jak zainstalować Pythona w inteligentny sposób
  • Lepsze zarządzanie projektami w Pythonie dzięki Poetry
  • Virtualenv i venv: wyjaśniono wirtualne środowiska Pythona
  • Python virtualenv i venv co robić, a czego nie
  • Wyjaśnienie wątków i podprocesów w Pythonie
  • Jak korzystać z debugera Pythona
  • Jak używać timeit do profilowania kodu Pythona
  • Jak używać cProfile do profilowania kodu Pythona
  • Zacznij korzystać z async w Pythonie
  • Jak używać asyncio w Pythonie
  • Jak przekonwertować Python na JavaScript (iz powrotem)