Recarga en caliente
La recarga en caliente (hot reload) actualiza la ventana abierta cada vez que guardas un archivo del proyecto. La app no se reinicia: los mismos objetos conservan sus datos y pasan a ejecutar el código nuevo.
uv run pyzed dev main.pypyzed dev main.pypython3 -m pyzed dev main.pypy -m pyzed dev main.pyDesde código, usa pz.run(MiApp, reload=True) o define la variable de entorno PYZED_RELOAD=1. Los formularios
también se actualizan al guardar (ver Ejecutar y la consola);
esta página trata de las apps escritas en Python.
Qué cambia al guardar
Sección titulada «Qué cambia al guardar»| Cambias | Qué pasa en la ventana abierta |
|---|---|
view(), un método, un módulo auxiliar, un estilo |
El código nuevo se usa desde el siguiente redibujado. |
Un método que otra cosa guarda (self.al_terminar = self.guardar, un temporizador, un hilo, functools.partial) |
Esa referencia también ejecuta el código nuevo. |
Un atributo nuevo en __init__ (self.etiquetas = []) |
El objeto vivo lo recibe al momento; nada más cambia. |
El valor inicial de un atributo (self.paso = 1 → self.paso = 5) |
Toma el valor nuevo si la app no lo cambió mientras corría; si lo cambió, se queda el de la app. |
Un pz.state(...) nuevo o un atributo nuevo en el setup() de un componente |
Todas las instancias del componente lo reciben. |
Un atributo de clase (size = (400, 300), title) |
Sale de la clase nueva. |
Código que no se puede importar, o un view() que lanza un error |
El error se ve en la ventana hasta que guardes la corrección. |
Cada recarga escribe una línea por clase que cambió, para que veas qué se aplicó:
pyzed: reloaded Notas: methods changed: agregar, view; new state: etiquetaspyzed: reloaded Notas: updated state: pasoUn ejemplo
Sección titulada «Un ejemplo»Abre esta app con pyzed dev notas.py, escribe algunas notas y luego haz los cambios de abajo de a uno, guardando
cada vez:
import pyzed as pzfrom pyzed import ui
class Notas(pz.App): title = "Notas" size = (420, 320)
def __init__(self): self.notas = [] self.borrador = ""
def escribir(self, texto): self.borrador = texto
def agregar(self): if self.borrador.strip(): self.notas.append(self.borrador.strip()) self.borrador = ""
def view(self): return pz.column([ pz.row([ui.input(self.borrador, self.escribir, on_submit=self.agregar, placeholder="Nota nueva"), ui.button("Agregar", self.agregar)], spacing=8), *[pz.text(nota) for nota in self.notas], ], spacing=8, padding=16)
if __name__ == "__main__": pz.run(Notas)- Un atributo nuevo. Agrega
self.favoritas = set()en__init__y un botón de estrella por nota enview(). Las notas que escribiste siguen ahí yself.favoritasexiste al instante. - Un método nuevo. Agrega
def limpiar(self): self.notas.clear()y un botón que lo llame. Funciona en el siguiente clic. - Un valor inicial nuevo. Agrega
self.limite = 10en__init__, guarda y cámbialo a5: la app ve5. Si la app hubiera cambiadolimitepor su cuenta, se conservaría su valor.
Cómo se actualiza el estado
Sección titulada «Cómo se actualiza el estado»Cuando una clase cambió, Pyzed vuelve a ejecutar su __init__ sobre una copia de prueba, con los argumentos con
los que se creó el objeto (en un componente, setup() con sus props actuales), y la compara con el objeto vivo:
- los atributos que el objeto vivo no tiene se copian;
- los valores simples (números, texto, booleanos y listas, tuplas, conjuntos y diccionarios pequeños de ellos) cuyo valor inicial cambió en el código se actualizan, pero solo si el valor vivo sigue siendo el inicial anterior;
- todo lo demás se deja como está. Después la copia se descarta, y lo que su
__init__imprimió no se muestra.
Las clases cuyo código no cambió no se tocan, así que guardar otro archivo nunca ejecuta tu __init__.
Los objetos de tus propias clases que Pyzed no creó (un Tarea dentro de una lista, por ejemplo) reciben los
atributos nuevos que solo usan self, globales o funciones integradas: self.hecha = False funciona,
self.etiqueta = texto.upper() necesita el argumento texto y se omite.
Cuando __init__ tiene efectos secundarios
Sección titulada «Cuando __init__ tiene efectos secundarios»Si __init__ abre un archivo, un dispositivo, un socket o arranca un hilo, ejecutarlo otra vez sobre una copia
suele ser inofensivo, pero puedes desactivarlo en esa clase:
class Reproductor(pz.App): reload_init = False # la recarga deja el estado como está: sin copia de prueba
def __init__(self): self.salida = abrir_dispositivo_de_audio()Mejor aún, mueve ese trabajo a on_start(), que se ejecuta una vez al abrir la ventana. Si el __init__ de la
copia falla, la recarga se aplica igual y la consola explica por qué no se actualizó el estado.
Migrar el estado a mano
Sección titulada «Migrar el estado a mano»Para cambios que Pyzed no puede adivinar (renombrar un atributo, cambiar su tipo), define on_reload() en la app
o en una ventana. Se ejecuta después de cada recarga y puede devolver un Command:
class Notas(pz.App): def on_reload(self): if isinstance(self.notas, list) and self.notas and isinstance(self.notas[0], str): self.notas = [{"texto": n, "hecha": False} for n in self.notas]Ver qué hizo una recarga
Sección titulada «Ver qué hizo una recarga»pz.hot_reload.current() devuelve el Reloader en marcha. Su lista changes tiene un Change por clase que
cambió en la última recarga (métodos changed, added y removed, new_state y updated_state), count dice
cuántas recargas salieron bien y error guarda el traceback de una que falló. Con verbose = False deja de
escribir en la consola.
Límites
Sección titulada «Límites»- Una tarea
asynco un generador en marcha sigue con el código con el que empezó hasta que termina. - Quitar un atributo de
__init__no lo borra del objeto vivo. - El código que ya se ejecutó (el bloque
if __name__ == "__main__":,on_start()) no se vuelve a ejecutar. - Una clase cuyos
__slots__cambian no puede pasar a la versión nueva; en ese caso reinicia la app.