Python 3.15: tipos nuevos, imports perezosos y un JIT más rápido
La nueva versión estable de Python trae tipos built-in (sentinel, frozendict), UTF-8 por defecto, imports perezosos explícitos y mejoras medibles en el compilador JIT experimental.

Un release grande, en cifras
Python 3.15.0 llega con 5.643 commits de 1.012 contribuidores respecto a la versión 3.14. No es un release de mantenimiento: toca el intérprete, la librería estándar, el sistema de tipos y la C API al mismo tiempo. Si vienes siguiendo el ciclo anual de Python, esta es una de esas versiones donde conviene revisar el changelog completo antes de migrar un proyecto grande, porque hay cambios de comportamiento por defecto (como la codificación UTF-8) que pueden afectar código que asumía otra cosa. El resto de esta nota recorre los cambios que más impactan en cómo escribes y ejecutas código todos los días.
sentinel y frozendict: dos tipos nuevos en el lenguaje
PEP 661 agrega un tipo built-in llamado sentinel. Durante años, el patrón para crear un valor centinela único (distinto de None, usado típicamente como marcador de 'no se pasó argumento') se resolvía a mano con trucos como object() o clases ad-hoc; ahora el lenguaje ofrece una forma estándar y reconocible de hacerlo. Por otro lado, PEP 814 suma frozendict, el equivalente inmutable de dict, de la misma manera que frozenset es el equivalente inmutable de set. Esto te da una estructura de datos de solo lectura sin tener que recurrir a MappingProxyType o a paquetes externos para garantizar que un diccionario no se modifique accidentalmente.
UTF-8 por defecto y unpacking en comprehensions
Con PEP 686, Python usa UTF-8 como codificación por defecto en todo el intérprete. Esto reduce una fuente clásica de bugs: código que funcionaba en Linux o macOS pero fallaba en Windows porque la codificación por defecto del sistema operativo era distinta. Por otro lado, PEP 798 habilita unpacking dentro de comprehensions, una sintaxis que antes no estaba permitida y obligaba a escribir bucles explícitos o concatenaciones manuales cuando necesitabas expandir un iterable dentro de una list, set o dict comprehension. Son dos cambios distintos en naturaleza, pero ambos apuntan a lo mismo: eliminar fricción en patrones que ya eran comunes en el código real.
Imports perezosos y configuración de arranque de paquetes
PEP 810 introduce imports perezosos explícitos, pensados para mejorar los tiempos de arranque de aplicaciones y scripts. La lógica es simple: si un módulo pesado se importa pero no se usa en ese arranque en particular, no tiene sentido pagar el costo de cargarlo de inmediato. Esto es distinto de los imports perezosos implícitos que algunos frameworks implementan con trucos de __getattr__; acá es una construcción explícita del lenguaje. En paralelo, PEP 829 agrega archivos de configuración de arranque para paquetes, lo que da un mecanismo estándar para que un paquete configure comportamiento al momento de instalarse o inicializarse, sin depender de hooks caseros en setup.py o en el __init__.py.
El JIT experimental gana rendimiento medible
El compilador JIT experimental, que viene desarrollándose desde versiones anteriores, recibió una actualización significativa en 3.15. Las notas del release citan números concretos: una mejora de 7 a 8% en la media geométrica de rendimiento en x86-64 Linux comparado con el intérprete estándar, y de 11 a 12% en AArch64 macOS comparado con el intérprete tail-calling. Esto importa porque el JIT sigue siendo experimental, no está activado por defecto en todas las plataformas, pero cada release reduce la brecha para que eventualmente sea una opción viable en producción. Si tu carga de trabajo es intensiva en CPU y corres en alguna de estas arquitecturas, vale la pena probar builds con el JIT habilitado y medir contra tu benchmark real.
Profiling integrado: nuevo paquete y Tachyon
PEP 799 trae dos cosas relacionadas pero distintas: un paquete dedicado para organizar las herramientas de profiling de Python, y Tachyon, un sampling profiler estadístico de alta frecuencia. Antes, hacer profiling serio en Python implicaba combinar herramientas de terceros con módulos dispersos de la librería estándar, cada uno con su propia interfaz. Tener un paquete dedicado y un sampling profiler de alta frecuencia como parte de la distribución estándar baja la barrera para diagnosticar problemas de rendimiento sin instalar dependencias externas. Las notas también mencionan 'more color', sin más detalle específico, como parte de las mejoras de la librería estándar en esta área.
Tipado más expresivo: TypedDict, TypeForm y bases disjuntas
Tres PEPs amplían el sistema de tipos. PEP 728 permite declarar TypedDict con tipos para los items extra, es decir, especificar qué tipo deben tener las claves que no están explícitamente listadas en la definición, algo que antes quedaba sin cubrir en el sistema de tipos. PEP 747 agrega TypeForm, que permite anotar 'formas de tipo' como valores de primera clase, útil cuando una función recibe o retorna un tipo en sí mismo y no una instancia de ese tipo. PEP 800 introduce bases disjuntas en el sistema de tipos, un mecanismo para que un type checker pueda razonar sobre jerarquías de clases que se declaran mutuamente excluyentes. Si usas mypy, pyright o pyrefly en un proyecto con TypedDicts complejos o jerarquías de tipos elaboradas, estos tres cambios amplían directamente lo que puedes expresar sin recurrir a Any o a comentarios de type: ignore.
C API, build y un aviso importante para macOS
En la C API, PEP 782 agrega PyBytesWriter para crear objetos bytes de Python, PEP 788 suma protección contra la finalización del intérprete, y el trío PEP 803/820/793 trabaja en la ABI estable para builds free-threaded. A nivel de build, PEP 831 habilita frame pointers por defecto, lo que mejora la observabilidad a nivel de sistema, por ejemplo al usar herramientas de profiling externas basadas en stack unwinding. En cuanto a distribución, los binarios oficiales de Windows de 64 bits ahora usan el intérprete tail-calling, y los binarios oficiales de macOS instalan soporte free-threading por defecto. Importante: si usas IDLE u otras aplicaciones tkinter en macOS 27.0, hay un problema conocido donde diálogos como 'About IDLE' o 'Settings' pueden colgar la aplicación por un cambio de comportamiento del sistema operativo que afecta a Tk en todas las versiones actuales de Python, no solo 3.15; si dependes de esto, conviene esperar antes de actualizar el sistema operativo o seguir el issue #158053 en el repositorio de CPython.
What you get
UTF-8 como default y el nuevo tipo sentinel atacan dos fuentes clásicas de bugs sutiles: codificación inconsistente entre sistemas y centinelas caseros mal implementados.
El JIT experimental ya muestra ganancias de doble dígito en algunas plataformas (hasta 11-12% en AArch64 macOS), aunque sigue sin ser el modo por defecto.
Los imports perezosos explícitos (PEP 810) apuntan directo a reducir tiempos de arranque, algo relevante si corres muchos scripts CLI o funciones serverless.
El sistema de tipos gana expresividad real con TypedDict de items extra tipados, TypeForm y bases disjuntas, útil si trabajas con type checkers en proyectos grandes.
Si usas tkinter o IDLE en macOS, revisa el issue #158053 antes de actualizar a macOS 27.0: hay un problema de compatibilidad conocido y sin solución al momento del release.
Want a class on this?
If enough people ask for it, it goes on the schedule. No email, no name needed.