Ir al contenido

Pyzed vs Flet para apps de escritorio en Python

Flet te deja construir apps Flutter en Python. Tu código Python se ejecuta en un proceso y envía el árbol de controles a un cliente Flutter que lo dibuja, en el escritorio, en la web o en un móvil. Ese alcance es la gran fortaleza de Flet. Pyzed dibuja en el mismo proceso que tu código Python, con un renderizador en Rust, y se centra en el escritorio.

Pyzed Flet
Arquitectura Un proceso: Python + renderizador en Rust (Iced) Proceso Python + proceso cliente Flutter, comunicados por un protocolo
Plataformas Windows, macOS, Linux Windows, macOS, Linux, web, Android, iOS
Aspecto Estilo de editor de código moderno, denso, pensado para escritorio Material 3 o Cupertino, pensado para móvil
Modelo Estado + view() reconstruido desde los datos Controles mutables + page.update(); Flet 1.0 añade componentes declarativos con hooks
Empaquetado pyzed build (PyInstaller), sin SDK extra flet build (requiere el SDK de Flutter)
Diseñador Pyzed Design –
Recarga en caliente Conserva el estado de la app flet run reinicia la app al guardar
Accesibilidad Teclado; sin lectores de pantalla todavía Lectores de pantalla mediante la semántica de Flutter
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)
Flet
"""Reference app: a counter with -, + and Reset."""
import flet as ft
def main(page: ft.Page):
page.title = "Counter"
page.window.width, page.window.height = 320, 200
count = ft.Text("0", size=24)
def change(step):
count.value = "0" if step is None else str(int(count.value) + step)
page.update()
page.add(ft.Column([
count,
ft.Row([
ft.IconButton(ft.Icons.REMOVE, on_click=lambda e: change(-1)),
ft.IconButton(ft.Icons.ADD, on_click=lambda e: change(1)),
ft.TextButton("Reset", on_click=lambda e: change(None)),
], alignment=ft.MainAxisAlignment.CENTER),
], horizontal_alignment=ft.CrossAxisAlignment.CENTER))
ft.run(main)
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)
Flet
"""Reference app: add tasks (button or Enter), tick them off, delete them, see how many are left."""
import flet as ft
def main(page: ft.Page):
page.title = "To-do"
page.window.width, page.window.height = 420, 480
tasks = ft.Column(scroll=ft.ScrollMode.AUTO, expand=True)
left = ft.Text("0 left", size=18, weight=ft.FontWeight.BOLD)
def refresh(_=None):
left.value = f"{sum(not row.controls[0].value for row in tasks.controls)} left"
page.update()
def remove(row):
tasks.controls.remove(row)
refresh()
def add(_):
if entry.value.strip():
row = ft.Row([ft.Checkbox(label=entry.value.strip(), on_change=refresh, expand=True)])
row.controls.append(ft.IconButton(ft.Icons.DELETE, on_click=lambda e: remove(row)))
tasks.controls.append(row)
entry.value = ""
refresh()
entry = ft.TextField(expand=True, on_submit=add)
page.add(left, ft.Row([entry, ft.Button("Add", on_click=add)]), tasks)
ft.run(main)

Medianas de los benchmarks (Linux, sin GPU: renderizado por software en ambos). La memoria de Flet incluye su proceso cliente de Flutter, que es donde vive la ventana. Su tamaño instalado cuenta los paquetes de Python más el cliente de escritorio que flet descarga en la primera ejecución.

Medición (menor es mejor en todas las filas)Pyzed 1.2.0Flet 1.0.4
Importar la biblioteca35 ms40 ms
Primer fotograma, 10 filas165 ms579 ms
Primer fotograma, 1.000 filas243 ms994 ms
Memoria (RSS), 10 filas151 MB268 MB
Memoria (RSS), 1.000 filas161 MB395 MB
Actualizar 1.000 filas18 ms166 ms
Líneas: contador19 líneas17 líneas
Líneas: lista de tareas31 líneas22 líneas
Flet Pyzed
ft.run(main) con main(page) pz.run(MiApp) con una clase pz.App
page.add(...), page.update() devuelve el árbol desde view(); sin actualizar a mano
ft.Column, ft.Row, ft.Container pz.column, pz.row, pz.container
ft.Text, ft.Button, ft.TextField, ft.Checkbox ui.label, ui.button, ui.input, ui.checkbox
on_click=manejador(e) on_press=metodo (sin argumento de evento)
page.theme_mode = ft.ThemeMode.DARK theme = "One Dark" o pz.themes.auto(...)
page.run_task(corrutina) devuelve una corrutina desde un callback
ft.ListView ui.virtual_list
ft.NavigationRail, ft.Tabs paneles de ui.workspace, ui.tab_bar
  1. Lleva el estado de los controles a la app. Los valores que lees de los controles (campo.value, casilla.value) pasan a ser atributos, actualizados por los callbacks de los controles.
  2. Borra las llamadas a page.update(). Pyzed redibuja después de cada callback.
  3. Espera una interfaz más densa. El espaciado de Material está pensado para el tacto; los componentes de Pyzed tienen el tamaño de un editor de escritorio. Usa variantes size="lg" o estilos si quieres más aire.
  • Elige Flet cuando un mismo código deba funcionar en la web y en móviles, o quieras los widgets Material de Flutter.
  • Elige Pyzed para apps pensadas para escritorio: un solo proceso, sin SDK de Flutter para empaquetar, un diseñador visual, recarga en caliente que conserva el estado y un aspecto denso y profesional.