Kuuli Technologies
Español
Noticias20 de octubre de 2026 · 7 min de lectura

Python 3.15 ya está aquí: lazy imports, frozendict y un profiler de 1 MHz

Python 3.15.0 salió el 9 de octubre de 2026. Repasamos sus novedades (lazy imports, frozendict, sentinel, Tachyon, UTF-8 por defecto, desempaquetado en comprehensions) y qué cambia para un equipo que tiene Python en producción.

El 9 de octubre de 2026 se publicó Python 3.15.0. Hugo van Kemenade, release manager de esta versión, ha contado en su blog cómo fue el día del lanzamiento: certificados caducados que tumbaron docs.python.org, un test intermitente en los buildbots, tres correcciones de última hora en lazy imports que obligaron a sacar una tercera release candidate "sorpresa" el 3 de octubre, unas dos horas solo para construir el instalador de Windows y la firma de todos los artefactos con Sigstore antes de subirlos a python.org.

El resultado merece la pena. Es una de las versiones con más cambios visibles para el día a día de los últimos años, y varias novedades tocan directamente a quien tiene Python en producción: CLIs, APIs, pipelines de datos o agentes de IA.

Las novedades de un vistazo

PEP 810

Lazy imports explícitos

El módulo se carga la primera vez que se usa, no al arrancar.

PEP 814

frozendict nativo

Un diccionario inmutable y hashable, sin librerías externas.

PEP 661

sentinel nativo

Valores centinela únicos con una representación legible.

PEP 799

Paquete profiling y Tachyon

Profiler estadístico de hasta 1.000.000 muestras por segundo.

PEP 798

Desempaquetado en comprehensions

* y ** directamente dentro de listas, sets, dicts y generadores.

PEP 686

UTF-8 por defecto

La E/S usa UTF-8 sea cual sea el locale del sistema.

PEP 831

Frame pointers activados

Pilas completas para profilers y depuradores del sistema.

PEP 803

ABI estable para free-threading

Extensiones en C compatibles con builds sin GIL (abi3t).

Lazy imports: arrancar sin cargar lo que no usas

Es la novedad estrella. Con la nueva palabra clave lazy, un import ya no ejecuta el módulo al arrancar: lo carga la primera vez que se accede a él. Para una CLI con muchos subcomandos, una función serverless o un worker que solo usa una parte de sus dependencias en cada petición, el ahorro en tiempo de arranque puede ser muy notable.

lazy_imports.pyPython 3.15
lazy import json
lazy from pathlib import Path

print("Arrancando...")                 # json y pathlib aún no se han cargado
data = json.loads('{"clave": "valor"}')  # json se carga aquí

También se puede activar de forma global con -X lazy_imports o la variable PYTHON_LAZY_IMPORTS, y las librerías que necesiten seguir funcionando en 3.14 pueden declarar __lazy_modules__ a nivel de módulo.

frozendict y sentinel, por fin en builtins

frozendict es un mapping inmutable y hashable que conserva el orden de inserción. No es una subclase de dict, y ya funciona con copy, json,pickle y pprint. Es ideal para configuración que no debe cambiar en tiempo de ejecución o para usar diccionarios como clave de caché. sentinel resuelve el clásicoMISSING = object() con valores únicos, legibles en los logs, que se conservan al copiarlos y se pueden serializar.

builtins.pyPython 3.15
config = frozendict(entorno="prod", region="eu-west-1")
config["region"] = "us-east-1"   # TypeError: no admite asignación
cache = {config: "resultado"}    # es hashable: sirve como clave

MISSING = sentinel("MISSING")    # centinela propio, sin object()

Desempaquetado dentro de las comprehensions

Aplanar una lista de listas o fusionar varios diccionarios ya no necesitaitertools.chain ni bucles anidados. Los operadores* y ** funcionan dentro de comprehensions de listas, sets y diccionarios, y también en generadores, incluidos los asíncronos.

comprehensions.pyPEP 798
listas = [[1, 2], [3, 4], [5]]
[*l for l in listas]          # [1, 2, 3, 4, 5]

dicts = [{"a": 1}, {"b": 2}, {"a": 3}]
{**d for d in dicts}          # {'a': 3, 'b': 2}

Tachyon: profiling en producción sin tocar el código

Python 3.15 agrupa sus herramientas en un nuevo paquete profiling(PEP 799): profiling.tracing recoge el antiguo cProfile yprofiling.sampling estrena Tachyon, un profiler estadístico que muestrea hasta 1.000.000 de veces por segundo y se puede enganchar a un proceso que ya está corriendo. Mide tiempo real, CPU, retención del GIL o excepciones, entiende código asíncrono y exporta flame graphs interactivos, heatmaps por línea, el formato de Firefox Profiler o una vista en vivo en la terminal.

terminalprofiling.sampling
python -m profiling.sampling run script.py
python -m profiling.sampling attach <pid>
python -m profiling.sampling run --mode cpu --flamegraph perfil.html script.py

Lo complementa la activación por defecto de los frame pointers (PEP 831): herramientas del sistema como perf ya pueden reconstruir la pila completa de llamadas sin recompilar CPython.

UTF-8 por defecto y free-threading más maduro

Con la PEP 686, abrir un archivo sin indicar encoding usa UTF-8 en todos los sistemas operativos. Desaparece una fuente histórica de errores con tildes y eñes en Windows, aunque es también el cambio que más puede romper código antiguo (ver la lista de abajo).

En paralelo, el Python sin GIL sigue avanzando. La PEP 803 crea un ABI estable para los builds free-threaded (abi3t), de modo que una extensión en C puede publicar un único wheel compatible con varias versiones, y meson-python, scikit-build-core y Maturin ya lo soportan. Además, el instalador oficial de macOS incluye free-threading por defecto.

Mensajes de error que piensan como tú

Los AttributeError sugieren ahora el método equivalente cuando escribes con hábitos de otro lenguaje, e incluso proponen el atributo correcto cuando está anidado dentro de otro objeto. Un detalle pequeño que ahorra búsquedas, sobre todo a quien llega a Python desde JavaScript o Java.

REPLPython 3.15
[1, 2, 3].push(4)
# AttributeError: 'list' object has no attribute 'push'. Did you mean '.append'?

'hola'.toUpperCase()
# AttributeError: 'str' object has no attribute 'toUpperCase'. Did you mean '.upper'?

Otros cambios que conviene conocer

Más color en la terminal

python --help, argparse, sqlite3, timeit, difflib y otras CLI de la biblioteca estándar muestran salida coloreada cuando detectan una TTY.

JIT experimental mejorado

El compilador JIT sigue siendo experimental, pero la documentación oficial lo describe como significativamente mejorado respecto a 3.14.

Tipado

TypeForm para anotar formas de tipo (PEP 747), TypedDict con extra items tipados (PEP 728) y bases disjuntas (PEP 800).

Archivos .start

Los paquetes declaran su código de arranque como pkg.mod:callable (PEP 829), en lugar de las líneas import de los .pth, que quedan obsoletas.

bytearray.take_bytes()

Devuelve bytes y vacía el buffer sin copiar memoria.

Binarios oficiales

En macOS el instalador incluye free-threading por defecto y en Windows de 64 bits se usa el intérprete con tail calls.

Antes de migrar tus proyectos

Prueba tu suite con UTF-8 forzado

Si algún proceso leía o escribía archivos confiando en el locale de Windows (cp1252), ahora el resultado cambia. Puedes volver al comportamiento anterior con PYTHONUTF8=0 mientras lo corriges.

Busca imports del módulo profile

Queda obsoleto y se eliminará en 3.17. El sustituto es profiling.tracing (el antiguo cProfile) o profiling.sampling.

Revisa __cached__ y las APIs eliminadas

El atributo __cached__ de los módulos desaparece (usa __spec__.cached), y se retiran APIs ya obsoletas de pathlib, typing, ast, importlib o threading, entre otros.

Espera a tus dependencias críticas

El propio equipo de release esperó a que Pydantic y aiohttp publicaran versiones compatibles. Comprueba que tus librerías con extensiones en C ya tienen wheels para 3.15.

Mide antes de activar lazy imports

Lánzalo primero con -X lazy_imports o PYTHON_LAZY_IMPORTS en un entorno de pruebas y compara el tiempo de arranque con Tachyon antes de reescribir imports.

Para saber más

¿Quieres aplicar esto en tu equipo?

En Kuuli Technologies llevamos estas metodologías a equipos reales. Escríbenos si quieres una sesión de trabajo o una consultoría sobre agentes IA y SDD.