Hur man använder PyInstaller för att skapa Python-körbara filer

Python, kraftfull och mångsidig som den är, saknar några viktiga funktioner ur lådan. För det första tillhandahåller Python ingen inbyggd mekanism för att kompilera ett Python-program till ett fristående körbart paket.

För att vara rättvis krävde det ursprungliga användningsfallet för Python aldrig fristående paket. Python-program har i stort sett körts på plats där en kopia av Python-tolk bodde. Men den ökande populariteten för Python har skapat större efterfrågan på att köra Python-appar på system utan installerad Python-körtid.

Flera tredje parter har konstruerat lösningar för att distribuera fristående Python-appar. Den mest populära lösningen i gänget, och den mest mogna, är PyInstaller. PyInstaller gör inte att förpackningen av en Python-app går helt smärtfri, men det går långt dit.

I den här artikeln utforskar vi grunderna för att använda PyInstaller inklusive hur PyInstaller fungerar, hur man använder PyInstaller för att skapa en fristående Python-körbar, hur man finjusterar Python-körbara filer och hur man undviker några av de vanliga fallgroparna med att använda PyInstaller.

Skapa ett PyInstaller-paket

PyInstaller är ett Python-paket, installerat med pip( pip install pyinstaller). PyInstaller kan installeras i din standard Python-installation, men det är bäst att skapa en virtuell miljö för projektet du vill paketera och installera PyInstaller där.

PyInstaller fungerar genom att läsa ditt Python-program, analysera all import det gör och bunta kopior av den importen med ditt program. PyInstaller läser i ditt program från dess startpunkt. Till exempel, om ditt programs startpunkt är myapp.py, skulle du springa för pyinstaller myapp.pyatt utföra analysen. PyInstaller kan upptäcka och automatiskt paketera många vanliga Python-paket, som NumPy, men du kan behöva ge tips i vissa fall. (Mer om detta senare.)

Efter att ha analyserat din kod och upptäckt alla bibliotek och moduler den använder genererar PyInstaller sedan en "spec-fil". Ett Python-skript med tillägget .spec, den här filen innehåller information om hur din Python-app behöver packas upp. Första gången du kör PyInstaller på din app kommer PyInstaller att generera en spec-fil från grunden och fylla den med några förnuftiga standardinställningar. Kasta inte den här filen; det är nyckeln till att förfina en PyInstaller-distribution!

Slutligen försöker PyInstaller producera en körbar från appen, med alla dess beroenden. När det är klart kommer en undermapp med namnet dist (som standard, du har frihet att ange ett annat namn) att visas i projektkatalogen. Den innehåller i sin tur en katalog som är din medföljande app - den har en .exefil att köra, tillsammans med alla bibliotek och andra kompletterande filer som krävs.

Allt du behöver göra för att distribuera ditt program är att paketera den här katalogen som en .zipfil eller någon annan bunt. Paketet behöver vanligtvis extraheras i en katalog där användaren har skrivbehörighet för att kunna köras.

Testa ett PyInstaller-paket

Det finns en stor chans att ditt första försök att använda PyInstaller för att paketera en app inte kommer att bli helt framgångsrikt.

För att kontrollera om ditt PyInstaller-paket fungerar, navigerar du till katalogen som innehåller den medföljande körbara .exefilen och kör filen där från kommandoraden. Om det inte går att köra bör de fel som du ser utskrivna på kommandoraden ge en ledtråd till vad som är fel.

Den vanligaste anledningen till att ett PyInstaller-paket misslyckas är att PyInstaller misslyckades med att samla en nödvändig fil. Sådana saknade filer faller i några kategorier:

  • Dold eller saknad import : Ibland kan PyInstaller inte upptäcka import av ett paket eller bibliotek, vanligtvis för att det importeras dynamiskt. Paketet eller biblioteket måste anges manuellt.
  • Saknade fristående filer : Om programmet är beroende av externa datafiler som behöver buntas med programmet har PyInstaller inget sätt att veta. Du måste inkludera filerna manuellt.
  • Saknade binärer : Här igen, om ditt program är beroende av en extern binär som en .DLL som PyInstaller inte kan upptäcka, måste du inkludera den manuellt.

Den goda nyheten är att PyInstaller ger ett enkelt sätt att hantera ovanstående problem. Den .specfil som skapas av PyInstaller innehåller fält vi kan fylla i för att ge detaljer som PyInstaller missat.

Öppna .specfilen i en textredigerare och leta efter definitionen av Analysisobjektet. Flera av parametrarna som skickas till Analysisär tomma listor, men de kan redigeras för att specificera de detaljer som saknas:

  • hiddenimportsför dold eller saknad import : Lägg till en eller flera strängar i listan med namnen på biblioteken du vill inkludera i din app. Om du vill lägga till pandasoch bokehtill exempel skulle du ange det som  ['pandas','bokeh']. Observera att biblioteken i fråga måste installeras i samma instans av Python där du kör PyInstaller.
  • datasför saknade fristående filer : Lägg här till en eller flera specifikationer för filer i ditt projektträd som du vill inkludera i ditt projekt. Varje fil måste skickas som en tupel som anger den relativa sökvägen till filen i din projektkatalog och den relativa sökvägen i distributionskatalogen där du vill placera filen. Om du till exempel hade en fil ./models/mainmodel.datsom du ville inkludera i din app och du vill placera den i en matchande underkatalog i din distributionskatalog, skulle du använda den ('./models/mainmodel.dat','./models')som en post i hiddenimportslistan. Observera att du kan använda globjokertecken för att ange mer än en fil.
  • binariesför saknade fristående binärfiler : Som med dataskan du använda för binariesatt skicka en lista med tuplar som anger platserna för binärfiler i projektträdet och deras destinationer i distributionskatalogen. Återigen kan du använda globjaktkort med stil.

Tänk på att någon av listorna som skickas till Analysiskan genereras programmatiskt tidigare i .specfilen. När allt kommer .specomkring är filen bara ett Python-skript med ett annat namn.

När du har gjort ändringar i .specfilen kör du om PyInstaller för att bygga om paketet. Men från och med nu, se till att skicka den modifierade .specfilen som parameter (t.ex. pyinstaller myapp.spec). Testa den körbara filen som tidigare. Om något fortfarande är trasigt kan du redigera .specfilen igen och upprepa processen tills allt fungerar.

Slutligen, när du är nöjd med att allt fungerar som avsett, kanske du vill redigera  .specfilen för att förhindra att din paketerade app presenterar ett kommandoradsfönster när den startas. I EXEobjekt inställningarna i .specfilen, ställ  console=False. Att undertrycka konsolen är användbart om din app har ett GUI och du inte vill att ett falskt kommandoradsfönster leder användarna på avvägar. Naturligtvis, ändra inte den här inställningen om din app kräver en kommandorad.

Förfina ett PyInstaller-paket

När du väl har packat din app med PyInstaller och körs ordentligt, är nästa sak du troligtvis vill göra att smala ner den lite. PyInstaller-paket är inte kända för att vara snygga.

Eftersom Python är ett dynamiskt språk är det svårt att förutsäga precis vad som behövs vid körning av ett visst program. Av den anledningen, när PyInstaller upptäcker en paketimport, innehåller den allt i det paketet, oavsett om det faktiskt används vid körning av ditt program. 

Här är de goda nyheterna. PyInstaller innehåller en mekanism för att selektivt exkludera hela paket eller enskilda namnområden i paket. Låt oss till exempel säga att ditt program importerar paket foo, som inkluderar foo.baroch foo.bip. Om du vet att ditt program bara använder inloggning foo.barkan du säkert utesluta foo.bip och spara lite utrymme.

För att göra detta använder du excludesparametern som skickas till Analysisobjektet i .specfilen. Du kan skicka en lista med namn - moduler på toppnivå eller prickade namnområden - för att utesluta från ditt paket. Till exempel, för att utesluta foo.bip, skulle du helt enkelt ange  ['foo.bip'].

Ett vanligt undantag du kan göra är tkinterPython-biblioteket för att skapa enkla grafiska användargränssnitt på flera plattformar. Som standard är  tkinteralla dess supportfiler packade med ett PyInstaller-projekt. Om du inte använder tkinteri ditt projekt kan du utesluta det genom att lägga 'tkinter'till i excludeslistan. Att utelämna tkinterkommer att minska storleken på paketet med cirka 7 MB.

Ett annat vanligt undantag är testsviter. Om ett paket som ditt program importerar har en testsvit kan testpaketet sluta inkluderas i ditt PyInstaller-paket. Om du inte kör testpaketet i ditt distribuerade program kan du säkert utesluta det.

Tänk på att paket som skapats med undantag bör testas noggrant innan de används. Om du slutar att exkludera funktionalitet som används i något framtida scenario som du inte förväntade dig, kommer din app att gå sönder.

Tips för PyInstaller

  • Bygg ditt PyInstaller-paket på det operativsystem du planerar att distribuera på.  PyInstaller stöder inte plattformsbyggnader. Om du behöver distribuera din fristående Python-app på MacOS, Linux och Windows-system måste du installera PyInstaller och bygga separata versioner av appen på vart och ett av dessa operativsystem. 
  • Bygg ditt PyInstaller-paket när du utvecklar din app.  Så snart du vet kommer du att distribuera ditt projekt med PyInstaller, bygg din .specfil och börja förfina PyInstaller-paketet parallellt med utvecklingen av din app. På det här sättet kan du lägga till undantag eller inneslutningar när du går och testa hur nya funktioner distribueras med appen när du skriver dem.
  • Använd inte PyInstaller-  --onefileläget.  PyInstaller innehåller en kommandoradsomkopplare, --onefilesom packar hela din app i en enda självutdragande körbar. Det här låter som en bra idé - du behöver bara leverera en fil! - men det har några fallgropar. När du kör appen måste den först packa upp alla filer i den körbara filen till en tillfällig katalog. Om appen är stor (till exempel 200 MB) kan uppackning innebära en fördröjning på flera sekunder. Använd standardläget för en enda katalog istället och packa bara upp allt som en .zipfil.
  • Skapa ett installationsprogram för din PyInstaller-app.  Om du vill ha något annat sätt att distribuera din app än en .zip-fil, kan du överväga att använda ett installationsverktyg som det öppna källkodsinstallationssystemet Nullsoft Scriptable. Det lägger till väldigt lite overhead till storleken på leveransen och låter dig konfigurera många aspekter av installationsprocessen, som att skapa genvägar till din körbara.
  • Förvänta dig inte hastigheter.  PyInstaller är ett  förpackningssystem , inte en  kompilator  eller en  optimerare . Kod förpackad med PyInstaller går inte snabbare än när den körs på det ursprungliga systemet. Om du vill påskynda Python-koden, använd ett C-accelererat bibliotek som passar uppgiften, eller ett projekt som Cython.

Hur man gör mer med Python

  • Cython tutorial: Hur man påskyndar Python
  • Hur man installerar Python på det smarta sättet
  • Bättre Python-projektledning med poesi
  • Virtualenv och venv: Python virtuella miljöer förklaras
  • Python virtualenv och venv do's and don'ts
  • Python-trådning och underprocesser förklaras
  • Hur man använder Python-felsökaren
  • Hur man använder timeit för att profilera Python-kod
  • Hur man använder cProfile för att profilera Python-kod
  • Kom igång med async i Python
  • Hur man använder asyncio i Python
  • Så här konverterar du Python till JavaScript (och tillbaka igen)