Cómo instalar y actualizar a Python 3.15 con uv: importaciones diferidas y compatibilidad de paquetes
Actualizado el

La respuesta corta: Python 3.15.0 salió el 9 de octubre de 2026. Si usas uv (opens in a new tab), actualiza uv primero y después instala:
uv self update
uv python install 3.15Luego crea un proyecto de prueba y prueba tus dependencias reales antes de mover nada importante:
uv init --python 3.15 py315-test
cd py315-test
uv add numpy pandas scikit-learn matplotlibEl stack científico principal ya se instala hoy con wheels precompilados. PyTorch y TensorFlow no. DuckDB se compila desde el código fuente. Si tu proyecto depende de alguno de ellos, quédate en 3.14 por ahora (uv python pin 3.14).
La novedad que justifica la actualización son las importaciones diferidas (lazy imports). Una sola palabra clave, lazy import pandas as pd, bajó la ruta --help de un script de prueba de 2.7 segundos a 0.01 segundos.
Qué se probó: todo lo marcado como "probado" se ejecutó el 11 de octubre de 2026 en un Apple M4 Max (macOS) con uv 0.13.0 y CPython 3.15.0 / 3.15.0t instalados con
uv python install. El comportamiento en Windows y Linux, el instalador de python.org, pyenv y conda se basa en la documentación oficial y no se probó.
Qué cambia en 3.15 y vas a notar
El changelog es largo. Si escribes scripts de datos o CLIs, estos cinco cambios son los que te vas a encontrar:
| Cambio | Qué significa para ti | Acción |
|---|---|---|
| Importaciones diferidas (PEP 810) | lazy import x retrasa la carga hasta el primer uso | Úsalo en CLIs, scripts y apps que tardan en arrancar |
| UTF-8 es la codificación por defecto (PEP 686) | open("file.txt") ahora lee y escribe UTF-8 en todos los sistemas | En Windows, con archivos cp1252 / cp932 / GBK: pasa encoding= de forma explícita |
| uv 0.13 usa 3.15 por defecto | Los proyectos nuevos de uv sin versión fijada reciben 3.15 automáticamente | Fija 3.14 donde tus dependencias aún no estén listas |
| La build free-threaded obtiene una ABI estable (PEP 803) | python3.15t ejecuta hilos en paralelo, pero la mayoría de paquetes aún no publica wheels de ABI estable para ella | Cuenta con compilaciones desde fuente en 3.15t |
Built-ins frozendict y sentinel, paquete profiling | Nuevos tipos integrados y el perfilador por muestreo Tachyon | Opcional; nada se rompe si los ignoras |
La lista completa está en el What's New in Python 3.15 oficial (opens in a new tab). El resto de esta guía cubre las tareas: instalar, comprobar compatibilidad, usar lazy imports, gestionar el cambio de codificación y decidir sobre free-threading.
- Cómo instalar y actualizar a Python 3.15 con uv: importaciones diferidas (lazy imports) y compatibilidad de paquetes
- Tutorial de Claude Code Mods: cómo crear, probar e instalar tu primer mod, con 15 ejemplos de la comunidad
- Cómo usar GPT Image 2.5: Flare vs. Sunburst y precios de la API
- Cómo usar DeepSeek Harness: instalación, configuración y tu primer agente
- Runcell Science: alternativa open source a Claude Science para investigación
- Cómo evitar que Mac se duerma: mantener Codex, Claude Code y agentes de IA corriendo
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: ¿Qué stack de agentes de IA deberías elegir en 2026?
- Cómo Claude Code analiza notebooks de Jupyter en Data Science: lo que sí hace y lo que no
- Claude Code routines: qué son y por qué importan los cron jobs de agentes de IA
- Claude Code Desktop Bypass Permissions: cómo activarlo
- Cómo Construir Dos Agentes en Python con el Protocolo A2A de Google - Tutorial Paso a Paso
- Las 10 principales bibliotecas de visualización de datos en Python que crecen en 2025
Paso 1: instalar Python 3.15
Con uv (probado)
Actualiza uv antes de instalar. Saltarse este paso es el error más fácil de cometer esta semana. Un uv antiguo solo conoce las builds alfa. Con el uv 0.9.25 que ya teníamos instalado, uv python list 3.15 mostraba solo cpython-3.15.0a4. Ejecutar ahí uv python install 3.15 habría instalado una alfa, no la versión final.
uv self update # needs 0.13.0 or newer
uv --version
uv python install 3.15uv 0.13.0 instaló la build normal y la free-threaded en 24.8 segundos:
uv python install 3.15 3.15tInstalled 2 versions in 24.83s
+ cpython-3.15.0+freethreaded-macos-aarch64-none (python3.15t)
+ cpython-3.15.0-macos-aarch64-none (python3.15)Si instalaste uv con Homebrew, pip o pipx, uv self update no funciona. Actualízalo por la misma vía con la que lo instalaste (brew upgrade uv, pipx upgrade uv).
uv 0.13 también cambia el valor por defecto. Las notas de la versión 0.13.0 de uv (opens in a new tab) indican que uv python install sin versión ahora descarga 3.15. Un uv venv o uvx python nuevo descarga 3.15 si no hay ya un Python compatible instalado. Las instalaciones existentes se siguen usando. Para mantener un proyecto en 3.14, déjalo registrado:
uv python pin 3.14Eso escribe .python-version, que uv lee cada vez que se ejecuta en esa carpeta.
Otras vías (según la documentación oficial, no probadas aquí)
- Instalador de python.org (Windows, macOS): descarga 3.15.0 desde python.org/downloads (opens in a new tab). Según las notas de la versión, el instalador oficial de macOS ahora instala el soporte free-threading por defecto, y los binarios de 64 bits para Windows usan el nuevo intérprete con tail calls.
- pyenv:
pyenv updatey despuéspyenv install 3.15.0. Espera a que tu versión de pyenv liste 3.15.0. - conda: crea un entorno con
python=3.15cuando conda-forge lo haya publicado. Compruébalo antes de planificar una migración en torno a ello.
Si quieres el panorama general de cómo cambiar de versión de Python en cada sistema, nuestra guía para actualizar Python y la comparativa de gestores de versiones de Python siguen siendo válidas. Esta página cubre lo específico de 3.15.
Paso 2: comprobar si tus paquetes se instalan
Este paso decide si puedes actualizar hoy. Creamos un proyecto 3.15 limpio, instalamos un stack típico de ciencia de datos y revisamos en PyPI los paquetes por los que más se pregunta.
Tabla de compatibilidad (probada el 11 de octubre de 2026)
| Paquete (versión) | Python 3.15 | Python 3.15t (free-threaded) | Notas |
|---|---|---|---|
| numpy 2.5.4 | Wheel | Wheel | |
| pandas 3.0.6 | Wheel | Wheel | |
| scipy 1.18.1 | Wheel | Wheel | |
| scikit-learn 1.9.1 | Wheel | Wheel | |
| matplotlib 3.11.2 | Wheel | Wheel | |
| pyarrow 26.0.0 | Wheel | Wheel | |
| polars 2.0.0 | Wheel (abi3) | Se compila desde fuente | Su runtime solo publica wheels cp310-abi3, que Python free-threaded no puede usar. La compilación en Rust tardó 6 min 51 s |
| ipykernel 9.17.1 (pyzmq, psutil, debugpy) | Wheel | No probado | Los kernels de Jupyter funcionan en 3.15 |
| duckdb 1.5.6 | Se compila desde fuente | No probado | Los wheels llegan solo hasta cp314. La compilación en C++ tardó unos 2.5 min |
| pygwalker 0.5.0.1 | Funciona | No probado | Depende de duckdb, así que hereda la compilación desde fuente |
| torch 2.14.1 | No se puede instalar | No se puede instalar | Solo hay wheels de cp310 a cp314 y cp314t |
| tensorflow 2.21.0 | No se puede instalar | No se puede instalar | Solo hay wheels de cp310 a cp313 |
Instalar numpy, pandas, scipy, scikit-learn, matplotlib, pyarrow y polars tardó 71 segundos en 3.15, descarga incluida y sin compilar nada. El mismo conjunto en 3.15t tardó 6 minutos 51 segundos, casi todo compilando Polars.
Cuando un paquete no tiene wheel, uv te dice exactamente por qué. Así se ve PyTorch en 3.15:
hint: You require CPython 3.15 (`cp315`), but we only found wheels for `torch`
(v2.14.1) with the following Python ABI tags: `cp310`, `cp311`, `cp312`, `cp313`, `cp314`, `cp314t`Revisa tu propio proyecto en un minuto
No necesitas instalar nada para saberlo. Haz una simulación (dry run) contra un entorno 3.15:
uv venv --python 3.15 .venv315
uv pip install --dry-run --python .venv315/bin/python -r requirements.txtSi se resuelve, todo bien. Si ves el aviso cp315 de arriba, ese paquete es tu bloqueo.
Compilar desde fuente no es un fallo, pero es lento y necesita un compilador (Rust para Polars, C++ para DuckDB). En CI, una compilación desde fuente puede convertir un job de un minuto en uno de diez. Fija 3.14 en CI hasta que lleguen los wheels.
Paso 3: usar lazy imports para que los scripts arranquen más rápido
Creo que las importaciones diferidas son la mejor razón para pasar a 3.15. El problema que resuelven es conocido.
Un script de línea de comandos suele importarlo todo al principio. Incluso my_tool.py --help paga el coste completo de cargar pandas, matplotlib y scikit-learn, aunque nunca los use.
Antes y después (probado)
La versión con importación inmediata (eager):
import sys
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.linear_model
if len(sys.argv) > 1 and sys.argv[1] == "--help":
print("usage: tool [--help] file.csv")
sys.exit(0)La versión diferida solo añade la palabra clave lazy:
import sys
lazy import pandas as pd
lazy import matplotlib.pyplot as plt
lazy from sklearn import linear_model
if len(sys.argv) > 1 and sys.argv[1] == "--help":
print("usage: tool [--help] file.csv")
sys.exit(0)
df = pd.DataFrame({"x": [1, 2, 3], "y": [2, 4, 6]})
model = linear_model.LinearRegression().fit(df[["x"]], df["y"])
print(model.coef_)Resultados en nuestra máquina, cinco ejecuciones de python script.py --help en cada caso:
| Versión | Tiempo | Líneas en -X importtime |
|---|---|---|
| Importaciones inmediatas | 2.69 a 2.74 s | 1,747 |
lazy import | 0.01 s | 27 |
La ruta completa del código sigue funcionando: la versión diferida ajustó la regresión e imprimió 2.0. pandas se carga en la línea que usa pd por primera vez.
Tus números absolutos serán otros. En este entorno, import sklearn.linear_model tardó 2.2 s por sí solo e import pandas tardó 0.86 s. El patrón se cumple en cualquier rama de tu programa que no toque una librería pesada.
Ver qué hacen las importaciones diferidas
Un nombre diferido es un proxy hasta que lo usas. Puedes comprobarlo:
import sys
lazy import json
print(type(globals()["json"])) # <class 'lazy_import'>
print("json" in sys.modules) # False
json.dumps(1)
print(type(globals()["json"]), "json" in sys.modules) # <class 'module'> TruePara saber qué importaciones son lentas, ejecuta python -X importtime your_script.py 2> imports.log y ordena por la segunda columna.
Tres casos en que lazy da SyntaxError (probado)
lazy solo funciona a nivel de módulo. Nos encontramos con los tres errores:
| Dónde | Mensaje de error |
|---|---|
| Dentro de una función | SyntaxError: lazy import not allowed inside functions |
Dentro de try / except | SyntaxError: lazy import not allowed inside try/except blocks |
| Import con asterisco | SyntaxError: lazy from ... import * is not allowed |
La regla de try/except es la que más importa. Un código como try: import ujson as json except ImportError: import json no puede ser diferido. Deja la alternativa como importación inmediata, o muévela a un módulo pequeño que importes de forma diferida.
La documentación oficial añade que los cuerpos de clase y las importaciones from __future__ tampoco pueden ser diferidos.
Los errores se trasladan al primer uso
Un módulo que no existe ya no falla al principio del archivo:
lazy import not_a_real_module
print("defined ok") # this prints
not_a_real_module.x # ModuleNotFoundError is raised hereEs cómodo para dependencias opcionales. También significa que una errata en un import puede quedar oculta hasta que se ejecute una ruta de código poco usada. Mantén al menos un test que ejercite cada importación diferida.
Hacerlo todo diferido sin tocar el código
Puedes pasar todo el programa a importaciones diferidas desde la línea de comandos:
python -X lazy_imports=all my_tool.py --help
# or
PYTHON_LAZY_IMPORTS=all python my_tool.py --helpNuestro script sin modificar bajó así a 0.01 s. Pero ten cuidado con los módulos que hacen trabajo al importarse. Creamos un módulo de plugin mínimo que imprime y se registra al importarse. Con lazy_imports=all, el registro nunca se ejecutó, porque el programa nunca tocó el nombre del módulo:
normal: plugin registered / main done
all: main doneLas librerías que registran plugins, codecs o backends de matplotlib al importarse pueden romperse igual. Usa =all para medir la ganancia posible y después añade lazy a mano en las importaciones que sabes que son seguras. Para un control más fino, la documentación describe sys.set_lazy_imports_filter().
Soportar 3.14 y 3.15 en el mismo archivo
La palabra clave lazy es un error de sintaxis en 3.14 y anteriores. Si tu código debe funcionar en ambas, usa en su lugar la lista __lazy_modules__ a nivel de módulo. Las versiones antiguas la ignoran y 3.15 trata esas importaciones como diferidas:
__lazy_modules__ = ["pandas"]
import sys
import pandas as pd # lazy on 3.15, eager on 3.14
print("pandas" in sys.modules) # False on 3.15 until pd is usedConfirmamos que pandas no aparecía en sys.modules en 3.15 con este patrón.
Paso 4: gestionar UTF-8 por defecto
En 3.15, open() sin argumento encoding usa UTF-8 en todas las plataformas. Confirmamos que sys.flags.utf8_mode == 1 por defecto y 0 con PYTHONUTF8=0.
En macOS y Linux esto casi no cambia nada. En Windows cambia el comportamiento de cualquier código que lea archivos antiguos sin indicar la codificación: exportaciones CSV de Excel en cp1252, archivos japoneses Shift-JIS (cp932) o archivos chinos GBK. Esas lecturas ahora pueden lanzar UnicodeDecodeError o producir texto corrupto.
La solución es ser explícito:
import pandas as pd
df = pd.read_csv("export.csv", encoding="cp932") # Japanese Excel export
with open("legacy.txt", encoding="locale") as f: # old behavior: system locale
text = f.read()Para encontrar el código afectado antes de actualizar, ejecuta tus tests en tu Python actual con -X warn_default_encoding. Para recuperar temporalmente el comportamiento anterior, define PYTHONUTF8=0.
Paso 5: decidir sobre la build free-threaded (3.15t)
Python free-threaded elimina el GIL, así que los hilos de Python puro pueden usar varios núcleos de CPU. Ejecutamos cuatro veces un bucle intensivo en CPU, primero en secuencia y luego en cuatro hilos:
| Build | Secuencial | 4 hilos | Aceleración |
|---|---|---|---|
| Python 3.15 | 0.72 s | 0.71 s | 1.0× |
| Python 3.15t | 0.65 s | 0.19 s | 3.4× |
El GIL siguió desactivado tras importar numpy, pandas, scikit-learn, polars, matplotlib y pyarrow (sys._is_gil_enabled() devolvió False).
Usa 3.15t si ejecutas código intensivo de Python puro en hilos y tus dependencias tienen wheels cp315t. Evítalo si dependes de Polars, DuckDB o librerías de deep learning. Evítalo también si tu trabajo pesado ya corre dentro de NumPy o pandas, que liberan el GIL por su cuenta.
¿Deberías actualizar ya?
| Tu situación | Recomendación |
|---|---|
| Scripts, CLIs y automatización con el stack numpy / pandas / sklearn | Actualiza. Las importaciones diferidas son una mejora real |
| Notebooks de Jupyter para análisis | Actualiza en un entorno nuevo; conserva tu kernel anterior unas semanas |
| Proyectos con PyTorch o TensorFlow | Quédate en 3.14 (uv python pin 3.14) |
| DuckDB o Polars en 3.15t dentro de CI | Espera a los wheels, o acepta el tiempo de compilación y un compilador en CI |
| Código de Windows que lee archivos con codificaciones antiguas | Añade primero encoding= explícito y después actualiza |
Usar 3.15 en Jupyter
ipykernel se instala y funciona en 3.15. Para registrar un kernel 3.15 desde un proyecto uv:
uv add ipykernel
uv run python -m ipykernel install --user --name py315 --display-name "Python 3.15"Si trabajas con notebooks, RunCell (opens in a new tab) funciona como un agente de IA dentro de Jupyter, así que ve el estado real de tu kernel. Eso ayuda a comprobar si un notebook existente sigue funcionando con el kernel nuevo. PyGWalker (opens in a new tab) también funciona en 3.15 (probado: pyg.to_html() renderizó un DataFrame), con la compilación de DuckDB mencionada arriba.
Solución de problemas
| Síntoma | Causa | Solución |
|---|---|---|
uv python install 3.15 instala 3.15.0a4 | uv es anterior a 0.13 | uv self update, o actualiza mediante Homebrew / pipx |
No solution found … no wheels with a matching Python ABI tag (cp315) | El paquete aún no tiene wheel para 3.15 (torch, tensorflow) | uv python pin 3.14 en ese proyecto |
| La instalación se queda minutos en duckdb o polars-runtime | Compilación desde fuente porque no hay wheel compatible | Espera (necesita un compilador de C++ o Rust), o usa 3.14 / 3.15 normal en lugar de 3.15t |
SyntaxError: lazy import not allowed … | lazy dentro de una función, un try o una clase | Lleva la importación al nivel de módulo, o déjala como inmediata |
| Un plugin o backend deja de registrarse | -X lazy_imports=all omitió una importación con efectos secundarios | Quita =all; usa lazy solo en importaciones elegidas |
UnicodeDecodeError en Windows tras actualizar | UTF-8 es ahora la codificación por defecto | Pasa encoding="cp1252" / "cp932" / "gbk" o encoding="locale" |
| Un proyecto uv nuevo aparece en 3.15 sin esperarlo | uv 0.13 cambió el valor por defecto | uv python pin 3.14 |
SyntaxWarning: 'return' in a 'finally' block desde una dependencia | La librería tiene código antiguo que el Python nuevo señala | Inofensivo; viene de la librería, no de tu código |
Preguntas frecuentes
¿Cuándo salió Python 3.15? Python 3.15.0 salió el 9 de octubre de 2026.
¿Cómo instalo Python 3.15 con uv? Actualiza uv a la 0.13.0 o posterior y ejecuta uv python install 3.15. Las versiones antiguas de uv solo conocen las builds alfa de 3.15.
¿Funciona pandas en Python 3.15? Sí. pandas 3.0.6 publica wheels cp315 y cp315t, igual que numpy, scipy, scikit-learn, matplotlib y pyarrow.
¿PyTorch es compatible con Python 3.15? Todavía no. A 11 de octubre de 2026, torch 2.14.1 solo tiene wheels hasta cp314 y cp314t, así que no se puede instalar en 3.15.
¿Qué son las importaciones diferidas (lazy imports) de Python 3.15? Escribir lazy import module hace que Python cree un proxy ligero y cargue el módulo solo cuando el nombre se usa por primera vez. Así se reduce el tiempo de arranque en las rutas de código que nunca tocan el módulo.
¿Puedo usar lazy imports y seguir soportando Python 3.14? Sí. Define __lazy_modules__ = ["module_name"] al principio del módulo. Python 3.15 trata esas importaciones como diferidas y las versiones anteriores ignoran la lista.
¿Cómo mantengo un proyecto en Python 3.14? Ejecuta uv python pin 3.14 en la carpeta del proyecto. Escribe un archivo .python-version que uv respeta.
Guías relacionadas
- Cómo actualizar Python en Windows, Mac, Linux y entornos virtuales
- Gestores de versiones de Python
- Cómo saber qué versión de Python tienes
- Cómo actualizar paquetes de Python
- Polars vs pandas
- Importación circular en Python: errores y soluciones