Ir al contenido

Pyzed vs PyQt y PySide (Qt para Python)

Qt es el framework gráfico más completo que puedes usar desde Python, mediante PySide6 (de The Qt Company, LGPL) o PyQt6 (de Riverbank, GPL o comercial). Lo tiene todo: gráficas, multimedia, un Chromium embebido, 3D, impresión, accesibilidad y treinta años en producción. Esa amplitud tiene un peso: una descarga grande, un modelo de objetos de C++ (señales, slots, padres, layouts) y una licencia en la que pensar.

Pyzed PyQt6 / PySide6
Licencia MIT PyQt: GPL v3 o comercial · PySide: LGPL v3 o comercial
Modelo Estado + view(); callbacks de Python normales Árbol de objetos, señales y slots, o QML declarativo
Aspecto Componentes modernos y temas, listos Estilos casi nativos; aspecto moderno con QSS o QML
Diseñador Pyzed Design, genera Python Qt Designer / Creator (archivos .ui), Qt Design Studio (QML)
Recarga en caliente pyzed dev, conserva el estado Vista previa de QML en las herramientas de Qt; el código Widgets necesita reiniciar
Amplitud Lo esencial de una app de escritorio + componentes de IDE Casi cualquier cosa, con decenas de módulos
Móvil – PySide6 en Android (vista previa técnica)
Accesibilidad Teclado; sin lectores de pantalla todavía Soporte completo de lectores de pantalla
Pyzed
"""Reference app: a counter with -, + and Reset."""
import pyzed as pz
from pyzed import ui
class Counter(pz.App):
title = "Counter"
size = (320, 200)
def __init__(self):
self.count = 0
def add(self, step):
self.count += step
def view(self):
return pz.center(pz.column([
ui.heading(str(self.count)),
pz.row([
ui.button(icon="minus", on_press=lambda: self.add(-1)),
ui.button(icon="plus", on_press=lambda: self.add(1), variant="solid"),
ui.button("Reset", lambda: setattr(self, "count", 0), variant="ghost"),
], spacing=8),
], spacing=16, align="center"))
pz.run(Counter)
PySide6 (Qt Widgets)
"""Reference app: a counter with -, + and Reset."""
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget
class Counter(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Counter")
self.resize(320, 200)
self.count = 0
self.label = QLabel("0", alignment=Qt.AlignmentFlag.AlignCenter)
self.label.setStyleSheet("font-size: 24px")
buttons = QHBoxLayout()
for text, step in (("-", -1), ("+", 1), ("Reset", None)):
button = QPushButton(text)
button.clicked.connect(lambda _=False, s=step: self.change(s))
buttons.addWidget(button)
layout = QVBoxLayout(self)
layout.addStretch()
layout.addWidget(self.label)
layout.addLayout(buttons)
layout.addStretch()
def change(self, step):
self.count = 0 if step is None else self.count + step
self.label.setText(str(self.count))
app = QApplication(sys.argv)
window = Counter()
window.show()
app.exec()

En Qt Widgets construyes los widgets una vez y los mantienes sincronizados con tus datos a mano (refresh() borra y vuelve a crear las filas). En Pyzed solo describes las filas para los datos actuales.

Pyzed
"""Reference app: add tasks (button or Enter), tick them off, delete them, see how many are left."""
import pyzed as pz
from pyzed import ui
class Todo(pz.App):
title = "To-do"
size = (420, 480)
def __init__(self):
self.tasks = [] # [title, done]
self.draft = ""
def add(self):
if self.draft.strip():
self.tasks.append([self.draft.strip(), False])
self.draft = ""
def toggle(self, task, done):
task[1] = done
def row(self, task):
return pz.row([
ui.checkbox(task[1], lambda done: self.toggle(task, done)),
ui.label(task[0], color="text_muted" if task[1] else "text", width="fill"),
ui.icon_button("trash-2", lambda: self.tasks.remove(task)),
], spacing=8, align="center")
def view(self):
left = sum(not done for _, done in self.tasks)
return pz.column([
ui.heading(f"{left} left", level=3),
pz.row([
ui.input(self.draft, lambda text: setattr(self, "draft", text), on_submit=self.add),
ui.button("Add", self.add, variant="solid"),
], spacing=8),
pz.scrollable(pz.column([self.row(t) for t in self.tasks], spacing=4), height="fill"),
], spacing=12, padding=16)
pz.run(Todo)
PySide6 (Qt Widgets)
"""Reference app: add tasks (button or Enter), tick them off, delete them, see how many are left."""
import sys
from PySide6.QtWidgets import (QApplication, QCheckBox, QHBoxLayout, QLabel, QLineEdit, QPushButton, QScrollArea,
QVBoxLayout, QWidget)
class Todo(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("To-do")
self.resize(420, 480)
self.tasks = [] # [title, done]
self.left = QLabel()
self.left.setStyleSheet("font-size: 16px; font-weight: bold")
self.entry = QLineEdit()
self.entry.returnPressed.connect(self.add)
add = QPushButton("Add")
add.clicked.connect(self.add)
entry_row = QHBoxLayout()
entry_row.addWidget(self.entry)
entry_row.addWidget(add)
self.list = QVBoxLayout()
inner = QWidget()
column = QVBoxLayout(inner)
column.addLayout(self.list)
column.addStretch()
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setWidget(inner)
layout = QVBoxLayout(self)
layout.addWidget(self.left)
layout.addLayout(entry_row)
layout.addWidget(scroll)
self.refresh()
def add(self):
if self.entry.text().strip():
self.tasks.append([self.entry.text().strip(), False])
self.entry.clear()
self.refresh()
def toggle(self, task, done):
task[1] = done
self.refresh()
def remove(self, task):
self.tasks.remove(task)
self.refresh()
def refresh(self):
while self.list.count():
item = self.list.takeAt(0)
item.widget().deleteLater()
for task in self.tasks:
row = QWidget()
line = QHBoxLayout(row)
check = QCheckBox(task[0])
check.setChecked(task[1])
check.toggled.connect(lambda done, t=task: self.toggle(t, done))
delete = QPushButton("Delete")
delete.clicked.connect(lambda _=False, t=task: self.remove(t))
line.addWidget(check, 1)
line.addWidget(delete)
self.list.addWidget(row)
self.left.setText(f"{sum(not done for _, done in self.tasks)} left")
app = QApplication(sys.argv)
window = Todo()
window.show()
app.exec()

Medianas de los benchmarks (Linux, sin GPU: renderizado por software). El tamaño instalado de Qt es solo pyside6-essentials; el paquete pyside6 completo con add-ons es varias veces mayor.

Medición (menor es mejor en todas las filas)Pyzed 1.2.0PySide6 (Qt) 6.12.0
Importar la biblioteca35 ms68 ms
Primer fotograma, 10 filas165 ms135 ms
Primer fotograma, 1.000 filas243 ms217 ms
Memoria (RSS), 10 filas151 MB72 MB
Memoria (RSS), 1.000 filas161 MB83 MB
Actualizar 1.000 filas18 ms24 ms
Líneas: contador19 líneas28 líneas
Líneas: lista de tareas31 líneas62 líneas
Qt Pyzed
QApplication + QMainWindow + app.exec() class MiApp(pz.App) + pz.run(MiApp)
QVBoxLayout, QHBoxLayout, QGridLayout pz.column, pz.row, pz.grid
QLabel, QPushButton, QLineEdit, QCheckBox ui.label, ui.button, ui.input, ui.checkbox
clicked.connect(slot) on_press=metodo
señales propias mensajes a update(), o pz.post(mensaje) desde un hilo
QTimer pz.every(...) en subscriptions()
QThread / QRunnable callbacks async def, generadores o hilos normales
QDockWidget, QTabWidget, QSplitter ui.workspace, ui.tab_bar, ui.split
QTreeView / QTableView + modelos ui.tree, ui.table, ui.virtual_list desde listas de Python
Hojas de estilo QSS temas y pz.Style
QShortcut, QAction on_key(combo), comandos y keys="ctrl-s" en botones
Archivos .ui de Qt Designer Archivos .pzform de Pyzed Design con manejadores en Python
  1. Empieza por los datos, no por los widgets. Haz una lista de lo que guardan tus subclases de QWidget (self.items, self.actual…) y conviértelo en atributos de tu App. Todo lo que los copia a los widgets (setText, setChecked, reinicios de modelos) desaparece.
  2. Convierte los slots en métodos. Un slot conectado con clicked.connect(self.guardar) pasa a ser on_press=self.guardar.
  3. Sustituye los modelos por listas. Un QAbstractListModel sobre una lista de Python pasa a ser la propia lista, más ui.virtual_list cuando es larga.
  4. Quédate con Qt donde dependas de él. Si la app necesita QtWebEngine, QtMultimedia, impresión o 3D, Qt sigue siendo la herramienta adecuada para esa app.
  • Elige Qt cuando necesites su amplitud, una app accesible con lectores de pantalla hoy, o una estabilidad probada durante décadas en un equipo grande, y su tamaño y su licencia encajen con tu proyecto.
  • Elige Pyzed cuando quieras una app de escritorio con aspecto moderno, con mucho menos código y ceremonia, licencia MIT permisiva, una instalación mucho más pequeña, recarga en caliente y ayuda de IA integrada en el flujo de trabajo.