Was macht Python-Installer-Erstellung (Professionell)?
Sie sind ein Experte für die kommerzielle Bereitstellung von Python-Anwendungen. Ihr Ziel ist der kleinste, am schnellsten startende und sauberste Windows-Installer. Der Kernansatz ist "Nuitka-Ordner-Modus (dist) + Inno-Setup-Paketierung" – keine Single-File-Builds, kein ungewolltes Konsolenfenster.
Wann aktivieren
Aktivieren, wenn der Benutzer explizit nach fortschrittlicher Python-Paketierung oder Größen-/Startzeit-Optimierung unter Windows fragt:
- Nuitka Extreme / Kommerzielle Kompilierung, kleinste Größe oder schnellster Start
dist-Ordner-Verschlankung, DLL-Footprint-Analyse, 32-Bit- vs. 64-Bit-Größenabwägungen- Inno-Setup-Paketierung mit vollständigen Metadaten und einer sauberen, rückstandsfreien Deinstallation
Dieses Skill zielt auf fortgeschrittene Größen-/Startzeit-Optimierung ab – nicht auf die einfache "Skript-zu-EXE"-Konvertierung.
Funktionsweise
- Build-Parameter bestätigen – App-Name, Version, Herausgeber, EXE-Name, Quell-/Ausgabeverzeichnisse, Icon. Niemals automatisch ausfüllen; den Benutzer fragen.
- Quell-Build überprüfen – Konsole deaktiviert, LTO aktiviert, VC++-Laufzeit vorhanden.
- Mit Nuitka kompilieren unter Verwendung der Modulausschluss- und Plugin-Strategie unten.
dist-Ordner verschlanken – Debug-Symbole, Caches, Tests und Dokumentation entfernen, mit Schutz für zur Laufzeit benötigte Metadaten.- DLLs analysieren, um die größten Abhängigkeiten zu finden und zu trimmen.
- Mit Inno Setup paketieren – LZMA2-Ultra-Kompression, vollständige Metadaten, rückstandsfreie Deinstallation und eine architekturgleiche VC++-Redistributable.
Beispiele
- "用 Nuitka 把这个 PySide2 项目打成最小体积的商业安装包" → den vollständigen Workflow ausführen: 32-Bit empfehlen, WebEngine/3D/Charts ausschließen,
distverschlanken, mit Inno Setup paketieren. - "我的 exe 有 400 MB,怎么瘦身到一半" → DLLs analysieren, zu
opencv-python-headlesswechseln,opengl32swentfernen,dist-Verschlankung anwenden. - "安装后在纯净系统打不开" → sicherstellen, dass die passende VC++-Redistributable im Inno-Setup-Skript gebündelt ist.
Kernphilosophie
Beständiges Festhalten am "Nuitka-Ordner-Modus (dist) + Inno-Setup-Paketierung"-Ansatz. Keine Single-File-Versionen, keine schwarzen Fenster.
Praxis-Referenzbeispiel (Produktionsreife PySide2-Desktop-Anwendung, 323 MB, inkl. OpenCV / Playwright)
Projektübersicht
- Gesamtgröße: 323 MB
- Paketierungstool: PyInstaller 4.7 (32-Bit)
- Hauptabhängigkeiten: PySide2 (22.52 MB), OpenCV (62.38 MB), Playwright (76.74 MB)
- Python-Version: Python 3.8 (32-Bit)
- DLL-Anzahl: 71, insgesamt 93.23 MB
Wichtige Optimierungsstrategien
- PASS: 32-Bit-Python verwenden → 20-30% Größenreduzierung
- PASS: base_library.zip komprimiert die Standardbibliothek → 0.74 MB
- PASS: Modulausschluss optimiert → kein pytest/unittest/setuptools
- PASS: Qt-Plugins optimiert → nur notwendige Plugins behalten
Größenverteilung
| Komponente | Größe | Anteil | Optimierungsvorschlag |
|---|---|---|---|
| playwright | 76.74 MB | 23.8% | Kann bei Bedarf entfernt werden |
| OpenCV | 62.38 MB | 19.3% | opencv-python-headless verwenden |
| PySide2 | 22.52 MB | 7.0% | WebEngine/3D/Charts ausschließen |
| Andere Abhängigkeiten | 161.36 MB | 49.9% | - |
Erwartete Ergebnisse im Vergleich
| Projekttyp | Nuitka Original | Nach Optimierung | Tatsächliche Messung Referenzprojekt |
|---|---|---|---|
| Tkinter + Standardbibliothek | 150-250 MB | 80-120 MB | - |
| PyQt/PySide | 200-400 MB | 120-250 MB | 323 MB (mit OpenCV usw.) |
| Mit numpy/pandas | 300-600 MB | 180-350 MB | - |
Kern-Workflow (Arbeitsablauf) - WARNUNG: Streng einhalten
Wenn der Benutzer eine Paketierung anfordert, führen Sie die folgenden Schritte aus:
Schritt 1: Parameter zwingend bestätigen (FEHLER: Keine Standardwerte verwenden)
WARNUNG: Wichtige Regel: Alle folgenden Parameter müssen einzeln mit dem Benutzer abgestimmt werden. Automatisches Ausfüllen oder Verwenden von Standardwerten ist verboten!
Der Benutzer muss zu den folgenden Informationen befragt werden und diese bestätigen (auf eine eindeutige Antwort des Benutzers warten, bevor fortgefahren wird):
| Parameter | Beschreibung | Beispiel |
|---|---|---|
| Softwarename (App Name) | Anzeigename der Software | 红墨批注 |
| Versionsnummer (Version) | Semantische Versionsnummer | 1.0.0 |
| Herausgeber/Firmenname (Publisher) | In der Systemsteuerung angezeigter Herausgeber | YourCompany |
| Hauptprogramm (Exe Name) | Name der Haupt-EXE-Datei | RedInk.exe |
| Quellpfad (Source Dir) | Absoluter Pfad zum Nuitka-dist-Ordner | D:\project\dist |
| Ausgabepfad (Output Dir) | Speicherort des Installers | D:\project\output |
| Icon-Pfad (Icon Path) | Absoluter Pfad zur .ico-Datei (optional, aber empfohlen) | D:\project\icon.ico |
| Webseite (URL) | Optional, für Link in der Systemsteuerung | https://example.com |
Nachfrage-Vorlage:
"Bitte geben Sie die folgenden Paketierungsparameter an. Ich benötige Ihre Bestätigung für jeden Punkt:
- Softwarename:
- Versionsnummer:
- Herausgeber/Firmenname:
- Hauptprogramm-Dateiname (z. B. xxx.exe):
- Quellpfad (Nuitka-dist-Ordner):
- Ausgabepfad (Speicherort des Installers):
- Icon-Pfad (.ico-Datei, kann leer gelassen werden):
- Webseite (kann leer gelassen werden):
Bitte füllen Sie jeden Punkt aus oder antworten Sie mit 'Überspringen' für leere Werte."
Schritt 2: Qualitäts- und Kompilierungsprüfung der Quelldateien (Kritisch) Vor der Code-Generierung muss der Benutzer die folgende kritische Bestätigung geben (da Inno Setup nur ein Paketierungstool ist und die Laufzeiteigenschaften des Programms nicht ändern kann):
"WARNUNG: Kompilierungsparameter-Prüfung:
- Kein Konsolenfenster: Bitte bestätigen Sie, dass Ihr dist-Ordner mit
nuitka --windows-console-mode=disablekompiliert wurde. (Sonst erscheint nach der Installation ein schwarzes Fenster.)- Hohe Leistung: Bitte bestätigen Sie, ob
--lto=yesverwendet wurde. (Sonst ist die Startzeit möglicherweise nicht optimal.)- Laufzeitbibliothek: Bitte stellen Sie sicher, dass der dist-Ordner die erforderlichen VC++-Laufzeitbibliotheken enthält, um die Ausführung auf einem sauberen System zu gewährleisten.
Bitte antworten Sie mit 'Bestätigt', wenn die Quelldateien bereit sind. Andernfalls kompilieren Sie bitte neu."
Schritt 3: Code generieren Nach der Bestätigung durch den Benutzer Code ausgeben, der vollständige Metadaten und eine Reparatur des Deinstallations-Icons enthält.
Nuitka Extreme Optimierungskompilierung (Basierend auf Referenzprojekt-Erfahrung)
I. 32-Bit vs. 64-Bit-Auswahlstrategie
Grund für die Verwendung von 32-Bit-Python im Referenzprojekt:
| Komponente | 64-Bit-Größe | 32-Bit-Größe | Einsparung |
|---|---|---|---|
| python3x.dll | ~4.5 MB | ~3.8 MB | 15% |
| Qt5Core.dll | ~8 MB | ~5 MB | 37% |
| numpy | ~30 MB | ~20 MB | 33% |
| Gesamt | Basislinie | -20~30% | - |
Empfohlene Bedingungen für 32-Bit:
- PASS: Programmspeicherverbrauch < 2 GB
- PASS: Es werden keine sehr großen Dateien verarbeitet (< 2 GB)
- PASS: Zielbenutzer sind normale Bürocomputer
32-Bit-Kompilierungsmethode:
# 1. 32-Bit-Python installieren (kann neben 64-Bit existieren)
# Download: https://www.python.org/downloads/windows/
# 2. Abhängigkeiten mit 32-Bit-Python installieren
py -3.12-32 -m pip install -r requirements.txt
# 3. Mit 32-Bit-Python kompilieren
py -3.12-32 -m nuitka --standalone ...deine Parameter
II. Modulausschlussliste (vom Referenzprojekt verifiziert)
Sichere Ausschlussliste (zur Laufzeit nicht benötigt):
unittest,test,pytest,_pytest,doctest,pdb,pdbpp,
setuptools,pip,distutils,pkg_resources,
email.mime,http.server,xmlrpc,pydoc
Erwarteter Effekt: 30-50 MB einsparen
III. GUI-Framework-spezifische Optimierung
Tkinter Extreme Optimierung (empfohlen, am leichtgewichtigsten)
nuitka --standalone --windows-console-mode=disable ^
--lto=yes ^
--jobs=8 ^
--enable-plugin=tk-inter ^
--enable-plugin=anti-bloat ^
--noinclude-pytest-mode=nofollow ^
--noinclude-setuptools-mode=nofollow ^
--nofollow-import-to=unittest,test,pytest,_pytest,doctest,pdb,pdbpp ^
--nofollow-import-to=setuptools,pip,distutils,pkg_resources ^
--nofollow-import-to=email.mime,http.server,xmlrpc,pydoc ^
--python-flag=no_docstrings ^
--output-dir=dist ^
--windows-icon-from-ico=icon.ico ^
--remove-output ^
main.py
Erwartete Größe: 80-120 MB (nach Optimierung)
PyQt5 / PySide2 Optimierung
nuitka --standalone --windows-console-mode=disable ^
--lto=yes ^
--jobs=8 ^
--enable-plugin=pyqt5 ^
--enable-plugin=anti-bloat ^
--noinclude-pytest-mode=nofollow ^
--noinclude-setuptools-mode=nofollow ^
--nofollow-import-to=unittest,test,pytest,_pytest,doctest,pdb ^
--nofollow-import-to=setuptools,pip,distutils,pkg_resources ^
--nofollow-import-to=PyQt5.QtWebEngine,PyQt5.QtWebEngineWidgets ^
--nofollow-import-to=PyQt5.Qt3D,PyQt5.QtCharts ^
--python-flag=no_docstrings ^
--include-qt-plugins=sensible,styles,platforms ^
--output-dir=dist ^
--windows-icon-from-ico=icon.ico ^
--remove-output ^
main.py
Erwartete Größe: 120-250 MB (nach Optimierung)
IV. Vorlage für Ein-Klick-Kompilierungsskript
Speichern als build_optimized.bat (Projektstammverzeichnis):
@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion
echo ========================================
echo Nuitka Extreme Optimierungskompilierung (Referenz: Referenzprojekt)
echo ========================================
REM === Konfigurationsbereich (An Ihre Werte anpassen) ===
set APP_NAME=IhrSoftwarename
set MAIN_FILE=main.py
set ICON_FILE=icon.ico
REM === Automatische CPU-Kern-Erkennung ===
REM Windows-Umgebungsvariable verwenden (wmic in Win11 22H2+ entfernt, falls nicht erkannt, wird --jobs=0 zu Single-Thread-Kompilierung)
set CPU_CORES=%NUMBER_OF_PROCESSORS%
if not defined CPU_CORES set CPU_CORES=4
set /a BUILD_JOBS=%CPU_CORES%
REM === Modulausschlussliste vom Referenzprojekt ===
set EXCLUDE_MODULES=unittest,test,pytest,_pytest,doctest,pdb,pdbpp
set EXCLUDE_MODULES=%EXCLUDE_MODULES%,setuptools,pip,distutils,pkg_resources
set EXCLUDE_MODULES=%EXCLUDE_MODULES%,email.mime,http.server,xmlrpc,pydoc
echo.
echo [1/4] Alte Builds bereinigen...
if exist dist rd /s /q dist
if exist build rd /s /q build
echo.
echo [2/4] Nuitka-Kompilierung läuft (Optimierungsstrategie vom Referenzprojekt angewendet)...
echo - CPU-Kerne: %CPU_CORES% (verwende %BUILD_JOBS% Threads)
echo - Modulausschluss: %EXCLUDE_MODULES%
echo.
nuitka --standalone ^
--windows-console-mode=disable ^
--lto=yes ^
--jobs=%BUILD_JOBS% ^
--enable-plugin=anti-bloat ^
--enable-plugin=tk-inter ^
--noinclude-pytest-mode=nofollow ^
--noinclude-setuptools-mode=nofollow ^
--nofollow-import-to=%EXCLUDE_MODULES% ^
--python-flag=no_docstrings ^
--output-dir=dist ^
--windows-icon-from-ico=%ICON_FILE% ^
--remove-output ^
%MAIN_FILE%
if %errorlevel% neq 0 (
echo.
echo [Fehler] Kompilierung fehlgeschlagen!
pause
exit /b 1
)
echo.
echo [3/4] Kompilierungsergebnis erfassen...
for /f %%a in ('powershell -NoProfile -Command "(Get-ChildItem -LiteralPath 'dist\%APP_NAME%.dist' -Recurse -File | Measure-Object -Property Length -Sum).Sum"') do set TOTAL_SIZE=%%a
set TOTAL_SIZE=%TOTAL_SIZE:,=%
set /a SIZE_MB=%TOTAL_SIZE% / 1048576
echo - Größe nach Kompilierung: %SIZE_MB% MB
echo.
echo [4/4] Verschlandungsbereinigung durchführen (Referenz: Referenzprojekt-Strategie)...
powershell -ExecutionPolicy Bypass -File slim_dist.ps1 -DistPath "dist\%APP_NAME%.dist"
echo.
echo ========================================
echo Kompilierung abgeschlossen!
echo ========================================
pause
V. dist-Verschlankungsskript (Bereinigung auf Referenzprojekt-Niveau)
Speichern als slim_dist.ps1 (gleiches Verzeichnis wie build_optimized.bat):
param(
[string]$DistPath
)
$ErrorActionPreference = "Continue" # Fehler nicht still unterdrücken: Löschfehler werden angezeigt, um falsche Erfolge zu vermeiden
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "dist-Verschlankungsbereinigung (Referenz: Referenzprojekt-Strategie)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
if (-not (Test-Path $DistPath)) {
Write-Host "[Fehler] Verzeichnis nicht gefunden: $DistPath" -ForegroundColor Red
exit 1
}
# Anfangsgröße erfassen
$InitialSize = (Get-ChildItem -Path $DistPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB
Write-Host "`nAnfangsgröße: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow
# Charakteristik des Referenzprojekts: Keine .pdb, .pyi, __pycache__, test usw.
Write-Host "`n[Wende Bereinigungsstrategie des Referenzprojekts an...]" -ForegroundColor Green
# 1. Debug-Symbole löschen
Write-Host "`n[1/7] Lösche .pdb-Debug-Symbole..." -ForegroundColor Green
$pdbFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pdb -File
$pdbSize = ($pdbFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pdbFiles.Count -gt 0) {
$pdbFiles | Remove-Item -Force
Write-Host " $($pdbFiles.Count) Dateien gelöscht, $([math]::Round($pdbSize, 2)) MB eingespart"
} else {
Write-Host " Keine .pdb-Dateien gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 2. Typannotationen löschen
Write-Host "`n[2/7] Lösche .pyi-Typannotationen..." -ForegroundColor Green
$pyiFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pyi -File
$pyiSize = ($pyiFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pyiFiles.Count -gt 0) {
$pyiFiles | Remove-Item -Force
Write-Host " $($pyiFiles.Count) Dateien gelöscht, $([math]::Round($pyiSize, 2)) MB eingespart"
} else {
Write-Host " Keine .pyi-Dateien gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 3. __pycache__ löschen
Write-Host "`n[3/7] Lösche __pycache__-Cache..." -ForegroundColor Green
$pycacheDirs = Get-ChildItem -Path $DistPath -Recurse -Directory -Filter "__pycache__"
$pycacheSize = 0
foreach ($dir in $pycacheDirs) {
$size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
$pycacheSize += $size
Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($pycacheDirs.Count -gt 0) {
Write-Host " $($pycacheDirs.Count) Verzeichnisse gelöscht, $([math]::Round($pycacheSize / 1MB, 2)) MB eingespart"
} else {
Write-Host " Keine __pycache__ gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 4. Testverzeichnisse löschen
Write-Host "`n[4/7] Lösche test/tests-Testverzeichnisse..." -ForegroundColor Green
$testDirs = Get-ChildItem -Path $DistPath -Recurse -Directory | Where-Object { $_.Name -match '^tests?$' }
$testSize = 0
foreach ($dir in $testDirs) {
$size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
$testSize += $size
Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($testDirs.Count -gt 0) {
Write-Host " $($testDirs.Count) Verzeichnisse gelöscht, $([math]::Round($testSize / 1MB, 2)) MB eingespart"
} else {
Write-Host " Keine Testverzeichnisse gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 5. Dokumentation und Beispiele löschen
Write-Host "`n[5/7] Lösche docs/examples-Dokumentationsverzeichnisse..." -ForegroundColor Green
$docDirs = Get-ChildItem -Path $DistPath -Recurse -Directory | Where-Object { $_.Name -match '^(docs|examples|samples|demo)$' }
$docSize = 0
foreach ($dir in $docDirs) {
$size = (Get-ChildItem -Path $dir.FullName -Recurse -File | Measure-Object -Property Length -Sum).Sum
$docSize += $size
Remove-Item -Path $dir.FullName -Recurse -Force
}
if ($docDirs.Count -gt 0) {
Write-Host " $($docDirs.Count) Verzeichnisse gelöscht, $([math]::Round($docSize / 1MB, 2)) MB eingespart"
} else {
Write-Host " Keine Dokumentationsverzeichnisse gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 6. .pyc-Dateien löschen
Write-Host "`n[6/7] Lösche .pyc-Bytecode..." -ForegroundColor Green
$pycFiles = Get-ChildItem -Path $DistPath -Recurse -Include *.pyc -File
$pycSize = ($pycFiles | Measure-Object -Property Length -Sum).Sum / 1MB
if ($pycFiles.Count -gt 0) {
$pycFiles | Remove-Item -Force
Write-Host " $($pycFiles.Count) Dateien gelöscht, $([math]::Round($pycSize, 2)) MB eingespart"
} else {
Write-Host " Keine .pyc-Dateien gefunden (bereits optimiert)" -ForegroundColor Gray
}
# 7. .dist-info-Metadaten optimieren
Write-Host "`n[7/7] Optimiere .dist-info-Metadaten..." -ForegroundColor Green
$distInfoDirs = Get-ChildItem -Path $DistPath -Recurse -Directory -Filter "*.dist-info"
$removedCount = 0
$removedSize = 0
foreach ($infoDir in $distInfoDirs) {
# Nur Installationsbuchhaltungsdateien löschen; METADATA und entry_points.txt behalten (werden von importlib.metadata zur Laufzeit gelesen, Löschen würde Plugin-Erkennung beeinträchtigen)
$filesToRemove = @("RECORD", "INSTALLER", "direct_url.json")
foreach ($fileName in $filesToRemove) {
$file = Join-Path $infoDir.FullName $fileName
if (Test-Path $file) {
$size = (Get-Item $file).Length
$removedSize += $size
Remove-Item $file -Force
$removedCount++
}
}
}
if ($removedCount -gt 0) {
Write-Host " $removedCount Metadatendateien gelöscht, $([math]::Round($removedSize / 1MB, 2)) MB eingespart"
} else {
Write-Host " Keine bereinigbaren Metadaten gefunden (bereits optimiert)" -ForegroundColor Gray
}
# Endgültige Größe erfassen
$FinalSize = (Get-ChildItem -Path $DistPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB
$SavedSize = $InitialSize - $FinalSize
$SavedPercent = if ($InitialSize -gt 0) { ($SavedSize / $InitialSize) * 100 } else { 0 }
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "Bereinigung abgeschlossen!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Anfangsgröße: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow
Write-Host "Endgröße: $([math]::Round($FinalSize, 2)) MB" -ForegroundColor Green
Write-Host "Platzersparnis: $([math]::Round($SavedSize, 2)) MB ($([math]::Round($SavedPercent, 1))%)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan