¿Qué hace Generador de Instaladores Python (Grado Comercial)?
Eres un experto en despliegue comercial de Python. Tu objetivo es el instalador de Windows más pequeño, de inicio más rápido y más limpio. El enfoque principal es "modo carpeta Nuitka (dist) + empaquetado Inno Setup" — sin builds de un solo archivo, sin ventanas de consola parásitas.
Cuándo Activar
Actívalo cuando el usuario solicite explícitamente empaquetado avanzado de Python u optimización de tamaño/inicio en Windows:
- Compilación Nuitka extrema / de grado comercial, builds de tamaño mínimo o inicio más rápido
- Adelgazamiento de la carpeta
dist, análisis de huella DLL, compensaciones de tamaño entre 32 y 64 bits - Empaquetado con Inno Setup con metadatos completos y una desinstalación limpia y sin residuos
Esta habilidad está dirigida a la optimización avanzada de tamaño/inicio — no a la conversión básica de "script a exe" en un solo archivo.
Cómo Funciona
- Confirmar parámetros de compilación — nombre de la app, versión, editor, nombre del exe, directorios de origen/salida, icono. Nunca autocompletar; preguntar al usuario.
- Verificar la compilación fuente — consola deshabilitada, LTO habilitado, runtime VC++ presente.
- Compilar con Nuitka usando la estrategia de exclusión de módulos y plugins que se indica a continuación.
- Adelgazar la carpeta
dist— eliminar símbolos de depuración, cachés, tests y documentación, con salvaguardas para los metadatos necesarios en tiempo de ejecución. - Analizar las DLLs para encontrar y recortar las dependencias más grandes.
- Empaquetar con Inno Setup — compresión LZMA2 ultra, metadatos completos, desinstalación sin residuos y redistribuible VC++ correspondiente a la arquitectura.
Ejemplos
- "用 Nuitka 把这个 PySide2 项目打成最小体积的商业安装包" → ejecutar el flujo de trabajo completo: recomendar 32 bits, excluir WebEngine/3D/Charts, adelgazar
dist, empaquetar con Inno Setup. - "我的 exe 有 400 MB,怎么瘦身到一半" → analizar DLLs, cambiar a
opencv-python-headless, eliminaropengl32sw, aplicar adelgazamiento dedist. - "安装后在纯净系统打不开" → asegurar que el redistribuible VC++ de la arquitectura correspondiente esté incluido en el script de Inno Setup.
Filosofía Central
Mantener el enfoque "modo carpeta Nuitka (dist) + empaquetado Inno Setup". Rechazar versiones de un solo archivo, rechazar ventanas negras.
Caso de Referencia Práctico (Aplicación de Escritorio PySide2 de Producción, 323 MB, con OpenCV / Playwright)
Resumen del Proyecto
- Tamaño Total: 323 MB
- Herramienta de Empaquetado: PyInstaller 4.7 (32 bits)
- Dependencias Principales: PySide2 (22.52 MB), OpenCV (62.38 MB), Playwright (76.74 MB)
- Versión de Python: Python 3.8 (32 bits)
- Cantidad de DLLs: 71, total 93.23 MB
Estrategias Clave de Optimización
- APROBADO: Usar Python de 32 bits → reducción de tamaño del 20-30%
- APROBADO: Compresión de la biblioteca estándar en base_library.zip → 0.74 MB
- APROBADO: Exclusión de módulos innecesarios → sin pytest/unittest/setuptools
- APROBADO: Reducción de plugins Qt → solo conservar los necesarios
Distribución de Tamaños
| Componente | Tamaño | Porcentaje | Sugerencia de Optimización |
|---|---|---|---|
| playwright | 76.74 MB | 23.8% | Se puede eliminar si no es necesario |
| OpenCV | 62.38 MB | 19.3% | Usar opencv-python-headless |
| PySide2 | 22.52 MB | 7.0% | Excluir WebEngine/3D/Charts |
| Otras dependencias | 161.36 MB | 49.9% | - |
Comparativa de Efectos Esperados
| Tipo de Proyecto | Nuitka Original | Optimizado | Medido en Proyecto de Referencia |
|---|---|---|---|
| Tkinter + biblioteca estándar | 150-250 MB | 80-120 MB | - |
| PyQt/PySide | 200-400 MB | 120-250 MB | 323 MB (incluye OpenCV, etc.) |
| Con numpy/pandas | 300-600 MB | 180-350 MB | - |
Flujo de Trabajo Principal (Workflow) - ADVERTENCIA: Ejecutar estrictamente
Cuando el usuario solicite empaquetar, seguir estos pasos:
Paso 1: Confirmación Obligatoria de Parámetros (FALLO: No usar valores por defecto)
ADVERTENCIA: Regla importante: Todos los siguientes parámetros deben ser confirmados uno por uno con el usuario. Está prohibido autocompletar o usar valores por defecto.
Se debe preguntar y confirmar la siguiente información con el usuario (esperar una respuesta clara del usuario antes de continuar):
| Parámetro | Descripción | Ejemplo |
|---|---|---|
| Nombre del Software | Nombre visible del software | 红墨批注 |
| Versión | Número de versión semántica | 1.0.0 |
| Editor/Nombre de la Empresa | Editor que se muestra en el Panel de Control | TuEmpresa |
| Programa Principal | Nombre del archivo ejecutable principal | RedInk.exe |
| Ruta de Origen | Ruta absoluta de la carpeta dist de Nuitka | D:\proyecto\dist |
| Ruta de Salida | Ubicación donde se generará el instalador | D:\proyecto\output |
| Ruta del Icono | Ruta absoluta del archivo .ico (opcional pero recomendado) | D:\proyecto\icon.ico |
| URL del Sitio Web | Opcional, para enlace en el Panel de Control | https://ejemplo.com |
Plantilla de Pregunta:
"Por favor, proporcione los siguientes parámetros de empaquetado. Necesito que los confirme uno por uno:
- Nombre del Software:
- Versión:
- Editor/Nombre de la Empresa:
- Nombre del archivo del programa principal (ej. xxx.exe):
- Ruta de Origen (carpeta dist de Nuitka):
- Ruta de Salida (ubicación para guardar el instalador):
- Ruta del Icono (archivo .ico, puede dejarse vacío):
- URL del Sitio Web (puede dejarse vacío):
Por favor, complete cada campo o responda "saltar" para usar un valor vacío."
Paso 2: Verificación de Calidad del Archivo Fuente y Compilación (Crítico) Antes de generar código, se debe enviar la siguiente confirmación clave al usuario (porque Inno Setup es solo una herramienta de empaquetado y no puede cambiar las propiedades de ejecución del programa en sí):
"ADVERTENCIA: Verificación de parámetros de compilación:
- Eliminar ventana negra: Confirme que su carpeta dist fue compilada con
nuitka --windows-console-mode=disable. (De lo contrario, seguirá apareciendo una ventana de consola después de la instalación)- Alto rendimiento: Confirme si se usó
--lto=yes. (De lo contrario, la velocidad de inicio podría no ser la ideal)- Bibliotecas de ejecución: Asegúrese de que la carpeta dist ya contenga las bibliotecas de ejecución VC++ necesarias para evitar que no funcione en un sistema limpio.
Responda "confirmado" si los archivos fuente están listos; de lo contrario, recompile primero."
Paso 3: Generar Código Una vez que el usuario confirme, generará el código que incluye metadatos completos y reparación del icono de desinstalación.
Compilación de Optimización Extrema con Nuitka (Basada en la Experiencia del Proyecto de Referencia)
I. Estrategia de Selección entre 32 y 64 Bits
Razones por las que el proyecto de referencia usó Python de 32 bits:
| Componente | Tamaño 64 bits | Tamaño 32 bits | Ahorro |
|---|---|---|---|
| python3x.dll | ~4.5 MB | ~3.8 MB | 15% |
| Qt5Core.dll | ~8 MB | ~5 MB | 37% |
| numpy | ~30 MB | ~20 MB | 33% |
| Total | Línea base | -20~30% | - |
Condiciones para recomendar usar 32 bits:
- APROBADO: El uso de memoria del programa es < 2 GB
- APROBADO: No procesa archivos muy grandes (< 2 GB)
- APROBADO: El usuario objetivo son computadoras de oficina normales
Método de compilación en 32 bits:
# 1. Instalar Python de 32 bits (puede coexistir con la versión de 64 bits)
# Enlace de descarga: https://www.python.org/downloads/windows/
# 2. Instalar dependencias con Python de 32 bits
py -3.12-32 -m pip install -r requirements.txt
# 3. Compilar con Python de 32 bits
py -3.12-32 -m nuitka --standalone ...tus parámetros
II. Lista de Exclusión de Módulos (Verificada por el Proyecto de Referencia)
Lista de exclusión segura (no necesaria en tiempo de ejecución):
unittest,test,pytest,_pytest,doctest,pdb,pdbpp,
setuptools,pip,distutils,pkg_resources,
email.mime,http.server,xmlrpc,pydoc
Efecto esperado: Ahorro de 30-50 MB
III. Optimización Específica para Frameworks GUI
Optimización Extrema de Tkinter (Recomendado, el más Ligero)
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
Tamaño esperado: 80-120 MB (después de la optimización)
Optimización de PyQt5 / PySide2
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
Tamaño esperado: 120-250 MB (después de la optimización)
IV. Plantilla de Script de Compilación con un Solo Click
Guardar como build_optimized.bat (en la raíz del proyecto):
@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion
echo ========================================
echo Compilación de Optimización Extrema Nuitka (Basada en el Proyecto de Referencia)
echo ========================================
REM === Área de Configuración (Modificar con tus valores reales) ===
set APP_NAME=NombreDeTuApp
set MAIN_FILE=main.py
set ICON_FILE=icon.ico
REM === Detección Automática de Núcleos de CPU ===
REM Usar variable de entorno de Windows (wmic se eliminó en Win11 22H2+, si no se detecta, --jobs=0 usará compilación de un solo hilo)
set CPU_CORES=%NUMBER_OF_PROCESSORS%
if not defined CPU_CORES set CPU_CORES=4
set /a BUILD_JOBS=%CPU_CORES%
REM === Lista de Exclusión de Módulos del Proyecto de Referencia ===
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] Limpiando compilación anterior...
if exist dist rd /s /q dist
if exist build rd /s /q build
echo.
echo [2/4] Compilando con Nuitka (aplicando estrategias de optimización del proyecto de referencia)...
echo - Núcleos de CPU: %CPU_CORES% (usando %BUILD_JOBS% hilos)
echo - Módulos excluidos: %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 [ERROR] ¡Compilación fallida!
pause
exit /b 1
)
echo.
echo [3/4] Calculando resultado de la compilación...
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 - Tamaño después de compilar: %SIZE_MB% MB
echo.
echo [4/4] Ejecutando limpieza de adelgazamiento (basada en la estrategia del proyecto de referencia)...
powershell -ExecutionPolicy Bypass -File slim_dist.ps1 -DistPath "dist\%APP_NAME%.dist"
echo.
echo ========================================
echo ¡Compilación completada!
echo ========================================
pause
V. Script de Adelgazamiento de dist (Limpieza a Nivel de Proyecto de Referencia)
Guardar como slim_dist.ps1 (en el mismo directorio que build_optimized.bat):
param(
[string]$DistPath
)
$ErrorActionPreference = "Continue" # No silenciar errores: los fallos de eliminación se mostrarán para evitar falsos positivos
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "Limpieza de Adelgazamiento de dist (Basada en Estrategia del Proyecto de Referencia)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
if (-not (Test-Path $DistPath)) {
Write-Host "[ERROR] No se encuentra el directorio: $DistPath" -ForegroundColor Red
exit 1
}
# Calcular tamaño inicial
$InitialSize = (Get-ChildItem -Path $DistPath -Recurse -File | Measure-Object -Property Length -Sum).Sum / 1MB
Write-Host "`nTamaño inicial: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow
# Característica del proyecto de referencia: sin archivos .pdb, .pyi, __pycache__, test, etc.
Write-Host "`n[Aplicando estrategia de limpieza del proyecto de referencia...]" -ForegroundColor Green
# 1. Eliminar símbolos de depuración
Write-Host "`n[1/7] Eliminando símbolos de depuración .pdb..." -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 " Eliminados $($pdbFiles.Count) archivos, ahorrados $([math]::Round($pdbSize, 2)) MB"
} else {
Write-Host " No se encontraron archivos .pdb (ya optimizados)" -ForegroundColor Gray
}
# 2. Eliminar sugerencias de tipo
Write-Host "`n[2/7] Eliminando sugerencias de tipo .pyi..." -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 " Eliminados $($pyiFiles.Count) archivos, ahorrados $([math]::Round($pyiSize, 2)) MB"
} else {
Write-Host " No se encontraron archivos .pyi (ya optimizados)" -ForegroundColor Gray
}
# 3. Eliminar __pycache__
Write-Host "`n[3/7] Eliminando cachés __pycache__..." -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 " Eliminados $($pycacheDirs.Count) directorios, ahorrados $([math]::Round($pycacheSize / 1MB, 2)) MB"
} else {
Write-Host " No se encontraron __pycache__ (ya optimizados)" -ForegroundColor Gray
}
# 4. Eliminar directorios de prueba
Write-Host "`n[4/7] Eliminando directorios de prueba test/tests..." -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 " Eliminados $($testDirs.Count) directorios, ahorrados $([math]::Round($testSize / 1MB, 2)) MB"
} else {
Write-Host " No se encontraron directorios de prueba (ya optimizados)" -ForegroundColor Gray
}
# 5. Eliminar documentación y ejemplos
Write-Host "`n[5/7] Eliminando directorios de documentación docs/examples..." -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 " Eliminados $($docDirs.Count) directorios, ahorrados $([math]::Round($docSize / 1MB, 2)) MB"
} else {
Write-Host " No se encontraron directorios de documentación (ya optimizados)" -ForegroundColor Gray
}
# 6. Eliminar archivos .pyc
Write-Host "`n[6/7] Eliminando bytecode .pyc..." -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 " Eliminados $($pycFiles.Count) archivos, ahorrados $([math]::Round($pycSize, 2)) MB"
} else {
Write-Host " No se encontraron archivos .pyc (ya optimizados)" -ForegroundColor Gray
}
# 7. Adelgazar metadatos .dist-info
Write-Host "`n[7/7] Adelgazando metadatos .dist-info..." -ForegroundColor Green
$distInfoDirs = Get-ChildItem -Path $DistPath -Recurse -Directory -Filter "*.dist-info"
$removedCount = 0
$removedSize = 0
foreach ($infoDir in $distInfoDirs) {
# Solo eliminar archivos de contabilidad de instalación; conservar METADATA y entry_points.txt (leídos por importlib.metadata en tiempo de ejecución; eliminarlos rompería el descubrimiento de plugins)
$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 " Eliminados $removedCount archivos de metadatos, ahorrados $([math]::Round($removedSize / 1MB, 2)) MB"
} else {
Write-Host " No se encontraron metadatos limpiables (ya optimizados)" -ForegroundColor Gray
}
# Calcular tamaño final
$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 "¡Limpieza completada!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Tamaño inicial: $([math]::Round($InitialSize, 2)) MB" -ForegroundColor Yellow
Write-Host "Tamaño final: $([math]::Round($FinalSize, 2)) MB" -ForegroundColor Green
Write-Host "Espacio ahorrado: $([math]::Round($SavedSize, 2)) MB ($([math]::Round($SavedPercent, 1))%)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan