Verwendung von PyInstaller zum Erstellen von ausführbaren Python-Dateien

Python, so leistungsfähig und vielseitig es auch ist, verfügt nicht über einige wichtige Funktionen. Zum einen bietet Python keinen nativen Mechanismus zum Kompilieren eines Python-Programms in ein eigenständiges ausführbares Paket.

Um fair zu sein, hat der ursprüngliche Anwendungsfall für Python niemals eigenständige Pakete gefordert. Python-Programme wurden im Großen und Ganzen direkt auf Systemen ausgeführt, auf denen eine Kopie des Python-Interpreters lebte. Die zunehmende Beliebtheit von Python hat jedoch zu einer größeren Nachfrage nach Python-Apps auf Systemen ohne installierte Python-Laufzeit geführt.

Mehrere Drittanbieter haben Lösungen für die Bereitstellung eigenständiger Python-Apps entwickelt. Die beliebteste und ausgereifteste Lösung ist PyInstaller. PyInstaller macht das Packen einer Python-App nicht völlig schmerzlos, aber es geht weit.

In diesem Artikel werden die Grundlagen der Verwendung von PyInstaller erläutert, einschließlich der Funktionsweise von PyInstaller, der Verwendung von PyInstaller zum Erstellen einer eigenständigen ausführbaren Python-Datei, der Feinabstimmung der von Ihnen erstellten ausführbaren Python-Dateien und der Vermeidung einiger häufig auftretender Probleme mit PyInstaller.

Erstellen eines PyInstaller-Pakets

PyInstaller ist ein Python-Paket, das mit pip( pip install pyinstaller) installiert wird . PyInstaller kann in Ihrer Standard-Python-Installation installiert werden. Am besten erstellen Sie jedoch eine virtuelle Umgebung für das Projekt, das Sie verpacken möchten, und installieren PyInstaller dort.

PyInstaller liest Ihr Python-Programm, analysiert alle importierten Importe und bündelt Kopien dieser Importe mit Ihrem Programm. PyInstaller liest Ihr Programm vom Einstiegspunkt aus ein. Wenn sich beispielsweise der Einstiegspunkt Ihres Programms befindet myapp.py, werden Sie ausgeführt pyinstaller myapp.py, um die Analyse durchzuführen. PyInstaller kann viele gängige Python-Pakete wie NumPy erkennen und automatisch verpacken. In einigen Fällen müssen Sie jedoch möglicherweise Hinweise geben. (Mehr dazu später.)

Nach der Analyse Ihres Codes und der Ermittlung aller verwendeten Bibliotheken und Module generiert PyInstaller eine „Spezifikationsdatei“. .specDiese Datei ist ein Python-Skript mit der Erweiterung und enthält Details dazu, wie Ihre Python-App gepackt werden muss. Wenn Sie PyInstaller zum ersten Mal in Ihrer App ausführen, generiert PyInstaller eine Spezifikationsdatei von Grund auf neu und füllt sie mit einigen vernünftigen Standardeinstellungen. Verwerfen Sie diese Datei nicht. Dies ist der Schlüssel zur Verfeinerung einer PyInstaller-Bereitstellung!

Schließlich versucht PyInstaller, eine ausführbare Datei aus der App zu erstellen, die alle ihre Abhängigkeiten enthält. Wenn der Vorgang abgeschlossen ist, dist wird im Projektverzeichnis ein Unterordner mit dem Namen (standardmäßig können Sie einen anderen Namen angeben) angezeigt. Dieses enthält wiederum ein Verzeichnis, das Ihre gebündelte App ist - es muss eine .exeDatei ausgeführt werden, zusammen mit allen Bibliotheken und anderen erforderlichen Zusatzdateien.

Alles, was Sie tun müssen, um Ihr Programm zu verteilen, ist, dieses Verzeichnis als .zipDatei oder ein anderes Bundle zu verpacken . Das Bundle muss normalerweise in einem Verzeichnis extrahiert werden, in dem der Benutzer über Schreibberechtigungen verfügt, um ausgeführt werden zu können.

Testen eines PyInstaller-Pakets

Es besteht die Möglichkeit, dass Ihr erster Versuch, mit PyInstaller eine App zu verpacken, nicht vollständig erfolgreich ist.

Um zu überprüfen, ob Ihr PyInstaller-Paket funktioniert, navigieren Sie zu dem Verzeichnis mit der gebündelten ausführbaren Datei und führen Sie die .exeDatei dort über die Befehlszeile aus. Wenn es nicht ausgeführt werden kann, sollten die Fehler, die in der Befehlszeile angezeigt werden, einen Hinweis darauf geben, was falsch ist.

Der häufigste Grund für das Fehlschlagen eines PyInstaller-Pakets ist, dass PyInstaller eine erforderliche Datei nicht bündeln konnte. Solche fehlenden Dateien fallen in einige Kategorien:

  • Versteckte oder fehlende Importe : Manchmal kann PyInstaller den Import eines Pakets oder einer Bibliothek nicht erkennen, normalerweise weil es dynamisch importiert wird. Das Paket oder die Bibliothek muss manuell angegeben werden.
  • Fehlende eigenständige Dateien : Wenn das Programm von externen Datendateien abhängt, die mit dem Programm gebündelt werden müssen, kann PyInstaller dies nicht wissen. Sie müssen die Dateien manuell einschließen.
  • Fehlende Binärdateien : Wenn Ihr Programm von einer externen Binärdatei wie einer DLL abhängt, die PyInstaller nicht erkennen kann, müssen Sie diese manuell einfügen.

Die gute Nachricht ist, dass PyInstaller eine einfache Möglichkeit bietet, die oben genannten Probleme zu lösen. Die .specvon PyInstaller erstellte Datei enthält Felder, die wir ausfüllen können, um die Details anzugeben, die PyInstaller übersehen hat.

Öffnen Sie die .specDatei in einem Texteditor und suchen Sie nach der Definition des AnalysisObjekts. Einige der übergebenen Parameter Analysissind leere Listen, können jedoch bearbeitet werden, um die fehlenden Details anzugeben:

  • hiddenimportsFür versteckte oder fehlende Importe : Fügen Sie dieser Liste eine oder mehrere Zeichenfolgen mit den Namen der Bibliotheken hinzu, die in Ihre App aufgenommen werden sollen. Wenn Sie hinzufügen möchten pandasund bokehzum Beispiel, würden Sie dies als angeben  ['pandas','bokeh']. Beachten Sie, dass die betreffenden Bibliotheken in derselben Python-Instanz installiert sein müssen , in der Sie PyInstaller ausführen.
  • datasfür fehlende eigenständige Dateien : Fügen Sie hier eine oder mehrere Spezifikationen für Dateien in Ihrem Projektbaum hinzu, die Sie in Ihr Projekt aufnehmen möchten. Jede Datei muss als Tupel übergeben werden, das den relativen Pfad zur Datei in Ihrem Projektverzeichnis und den relativen Pfad innerhalb des Verteilungsverzeichnisses angibt, in dem Sie die Datei ablegen möchten. Wenn Sie beispielsweise eine Datei hatten ./models/mainmodel.dat, die Sie in Ihre App aufnehmen möchten, und diese in einem passenden Unterverzeichnis in Ihrem Verteilungsverzeichnis ablegen möchten, würden Sie sie ('./models/mainmodel.dat','./models')als einen Eintrag in der hiddenimportsListe verwenden. Beachten Sie, dass Sie globPlatzhalter im Stil -style verwenden können, um mehr als eine Datei anzugeben.
  • binariesfür fehlende eigenständige Binärdateien : Wie bei dataskönnen Sie binarieseine Liste von Tupeln übergeben, die die Speicherorte der Binärdateien in der Projektstruktur und ihre Ziele im Verteilungsverzeichnis angeben. Auch hier können Sie globPlatzhalter im Stil verwenden.

Beachten Sie, dass alle an übergebenen Listen Analysisfrüher in der .specDatei programmgesteuert generiert werden können. Immerhin ist die .specDatei nur ein Python-Skript mit einem anderen Namen.

Nachdem Sie Änderungen an der .specDatei vorgenommen haben, führen Sie PyInstaller erneut aus, um das Paket neu zu erstellen. Übergeben Sie jedoch von nun an die geänderte .specDatei als Parameter (z pyinstaller myapp.spec. B. ). Testen Sie die ausführbare Datei wie zuvor. Wenn immer noch etwas kaputt ist, können Sie die .specDatei erneut bearbeiten und den Vorgang wiederholen, bis alles funktioniert.

Wenn Sie zufrieden sind, dass alles wie beabsichtigt funktioniert, möchten Sie möglicherweise die .specDatei bearbeiten  , um zu verhindern, dass Ihre gepackte App beim Start ein Befehlszeilenfenster anzeigt. EXELegen Sie in den Objekteinstellungen in der .specDatei fest  console=False. Das Unterdrücken der Konsole ist nützlich, wenn Ihre App über eine grafische Benutzeroberfläche verfügt und Sie kein falsches Befehlszeilenfenster wünschen, das Benutzer in die Irre führt. Ändern Sie diese Einstellung natürlich nicht, wenn für Ihre App eine Befehlszeile erforderlich ist.

Verfeinern eines PyInstaller-Pakets

Sobald Sie Ihre App mit PyInstaller gepackt haben und ordnungsgemäß ausgeführt werden, möchten Sie sie wahrscheinlich als Nächstes ein wenig verkleinern. PyInstaller-Pakete sind nicht als schlank bekannt.

Da Python eine dynamische Sprache ist, ist es schwierig vorherzusagen, was ein bestimmtes Programm zur Laufzeit benötigt. Wenn PyInstaller einen Paketimport erkennt, enthält es daher alles in diesem Paket, unabhängig davon, ob es zur Laufzeit von Ihrem Programm verwendet wird oder nicht. 

Hier sind die guten Nachrichten. PyInstaller enthält einen Mechanismus zum selektiven Ausschließen ganzer Pakete oder einzelner Namespaces innerhalb von Paketen. Nehmen wir zum Beispiel an, Ihr Programm importiert ein Paket foo, das foo.barund enthält foo.bip. Wenn Sie sicher sind, dass Ihr Programm nur Logik verwendet foo.bar, können Sie sicher foo.bip Speicherplatz ausschließen und sparen.

Dazu verwenden Sie den excludesParameter, der an das AnalysisObjekt in der .specDatei übergeben wird. Sie können eine Liste von Namen übergeben - Module der obersten Ebene oder gepunktete Namespaces -, um sie aus Ihrem Paket auszuschließen. Zum Ausschließen foo.bipwürden Sie beispielsweise einfach angeben  ['foo.bip'].

Ein häufiger Ausschluss ist tkinterdie Python-Bibliothek zum Erstellen einfacher plattformübergreifender grafischer Benutzeroberflächen. Standardmäßig sind  tkinteralle Support-Dateien mit einem PyInstaller-Projekt gepackt. Wenn Sie es nicht tkinterin Ihrem Projekt verwenden, können Sie es ausschließen, indem Sie 'tkinter'es zur excludesListe hinzufügen . Durch das Weglassen tkinterwird die Größe des Pakets um ca. 7 MB reduziert.

Ein weiterer häufiger Ausschluss sind Testsuiten. Wenn ein Paket, das Ihr Programm importiert, eine Testsuite enthält, wird die Testsuite möglicherweise in Ihr PyInstaller-Paket aufgenommen. Sofern Sie die Testsuite nicht tatsächlich in Ihrem bereitgestellten Programm ausführen, können Sie sie sicher ausschließen.

Beachten Sie, dass mit Ausschlüssen erstellte Pakete vor der Verwendung gründlich getestet werden sollten. Wenn Sie Funktionen ausschließen, die in einem zukünftigen Szenario verwendet werden, das Sie nicht erwartet haben, wird Ihre App beschädigt.

PyInstaller-Tipps

  • Erstellen Sie Ihr PyInstaller-Paket auf dem Betriebssystem, auf dem Sie die Bereitstellung durchführen möchten.  PyInstaller unterstützt keine plattformübergreifenden Builds. Wenn Sie Ihre eigenständige Python-App auf MacOS-, Linux- und Windows-Systemen bereitstellen müssen, müssen Sie PyInstaller installieren und auf jedem dieser Betriebssysteme separate Versionen der App erstellen. 
  • Erstellen Sie Ihr PyInstaller-Paket, während Sie Ihre App entwickeln.  Sobald Sie wissen, dass Sie Ihr Projekt mit PyInstaller bereitstellen, erstellen Sie Ihre .specDatei und verfeinern Sie das PyInstaller-Paket parallel zur Entwicklung Ihrer App. Auf diese Weise können Sie unterwegs Ausschlüsse oder Einschlüsse hinzufügen und testen, wie neue Funktionen mit der App bereitgestellt werden, während Sie sie schreiben.
  • Verwenden Sie nicht den PyInstaller-  --onefileModus.  PyInstaller enthält einen Befehlszeilenschalter --onefile, der Ihre gesamte App in eine einzige selbstextrahierende ausführbare Datei packt. Das klingt nach einer großartigen Idee - Sie müssen nur eine Datei liefern! - aber es hat einige Fallstricke. Wenn Sie die App ausführen, müssen zuerst alle Dateien in der ausführbaren Datei in ein temporäres Verzeichnis entpackt werden. Wenn die App groß ist (z. B. 200 MB), kann das Auspacken eine Verzögerung von mehreren Sekunden bedeuten. Verwenden Sie stattdessen den Standard-Einzelverzeichnismodus und packen Sie einfach alles als .zipDatei zusammen.
  • Erstellen Sie ein Installationsprogramm für Ihre PyInstaller-App.  Wenn Sie Ihre App auf andere Weise als mit einer ZIP-Datei bereitstellen möchten, sollten Sie ein Installationsprogramm wie das Open Source Nullsoft Scriptable Install System verwenden. Es erhöht den Aufwand für das zu liefernde Element erheblich und ermöglicht Ihnen das Konfigurieren vieler Aspekte des Installationsprozesses, z. B. das Erstellen von Verknüpfungen zu Ihrer ausführbaren Datei.
  • Erwarten Sie keine Beschleunigungen.  PyInstaller ist ein  Verpackungssystem , kein  Compiler  oder  Optimierer . Mit PyInstaller gepackter Code wird nicht schneller ausgeführt als auf dem ursprünglichen System. Wenn Sie Python-Code beschleunigen möchten, verwenden Sie eine für die Aufgabe geeignete C-beschleunigte Bibliothek oder ein Projekt wie Cython.

Wie man mehr mit Python macht

  • Cython-Tutorial: So beschleunigen Sie Python
  • So installieren Sie Python auf intelligente Weise
  • Besseres Python-Projektmanagement mit Poetry
  • Virtualenv und venv: Erklärte virtuelle Python-Umgebungen
  • Python virtualenv und venv tun und nicht tun
  • Python-Threading und Unterprozesse erklärt
  • Verwendung des Python-Debuggers
  • Verwendung von timeit zum Profilieren von Python-Code
  • Verwendung von cProfile zum Profilieren von Python-Code
  • Beginnen Sie mit Async in Python
  • So verwenden Sie Asyncio in Python
  • So konvertieren Sie Python in JavaScript (und wieder zurück)