Skip to content

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

Actualizado el

Instala Python 3.15 con un solo comando de uv y comprueba si numpy, pandas, PyTorch, DuckDB y Polars se instalan de verdad. Probado en macOS: tabla de compatibilidad de wheels, lazy imports que bajan el arranque de un script de 2.7 s a 0.01 s, los tres casos en que lazy import da SyntaxError y la build free-threaded.

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.15

Luego 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 matplotlib

El 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:

CambioQué significa para tiAcció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 sistemasEn Windows, con archivos cp1252 / cp932 / GBK: pasa encoding= de forma explícita
uv 0.13 usa 3.15 por defectoLos proyectos nuevos de uv sin versión fijada reciben 3.15 automáticamenteFija 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 ellaCuenta con compilaciones desde fuente en 3.15t
Built-ins frozendict y sentinel, paquete profilingNuevos tipos integrados y el perfilador por muestreo TachyonOpcional; 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.

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.15

uv 0.13.0 instaló la build normal y la free-threaded en 24.8 segundos:

uv python install 3.15 3.15t
Installed 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.14

Eso 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 update y después pyenv install 3.15.0. Espera a que tu versión de pyenv liste 3.15.0.
  • conda: crea un entorno con python=3.15 cuando 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.15Python 3.15t (free-threaded)Notas
numpy 2.5.4WheelWheel
pandas 3.0.6WheelWheel
scipy 1.18.1WheelWheel
scikit-learn 1.9.1WheelWheel
matplotlib 3.11.2WheelWheel
pyarrow 26.0.0WheelWheel
polars 2.0.0Wheel (abi3)Se compila desde fuenteSu 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)WheelNo probadoLos kernels de Jupyter funcionan en 3.15
duckdb 1.5.6Se compila desde fuenteNo probadoLos wheels llegan solo hasta cp314. La compilación en C++ tardó unos 2.5 min
pygwalker 0.5.0.1FuncionaNo probadoDepende de duckdb, así que hereda la compilación desde fuente
torch 2.14.1No se puede instalarNo se puede instalarSolo hay wheels de cp310 a cp314 y cp314t
tensorflow 2.21.0No se puede instalarNo se puede instalarSolo 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.txt

Si 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ónTiempoLíneas en -X importtime
Importaciones inmediatas2.69 a 2.74 s1,747
lazy import0.01 s27

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'> True

Para 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óndeMensaje de error
Dentro de una funciónSyntaxError: lazy import not allowed inside functions
Dentro de try / exceptSyntaxError: lazy import not allowed inside try/except blocks
Import con asteriscoSyntaxError: 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 here

Es 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 --help

Nuestro 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 done

Las 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 used

Confirmamos 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:

BuildSecuencial4 hilosAceleración
Python 3.150.72 s0.71 s1.0×
Python 3.15t0.65 s0.19 s3.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ónRecomendación
Scripts, CLIs y automatización con el stack numpy / pandas / sklearnActualiza. Las importaciones diferidas son una mejora real
Notebooks de Jupyter para análisisActualiza en un entorno nuevo; conserva tu kernel anterior unas semanas
Proyectos con PyTorch o TensorFlowQuédate en 3.14 (uv python pin 3.14)
DuckDB o Polars en 3.15t dentro de CIEspera a los wheels, o acepta el tiempo de compilación y un compilador en CI
Código de Windows que lee archivos con codificaciones antiguasAñ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íntomaCausaSolución
uv python install 3.15 instala 3.15.0a4uv es anterior a 0.13uv 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-runtimeCompilación desde fuente porque no hay wheel compatibleEspera (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 claseLleva 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 secundariosQuita =all; usa lazy solo en importaciones elegidas
UnicodeDecodeError en Windows tras actualizarUTF-8 es ahora la codificación por defectoPasa encoding="cp1252" / "cp932" / "gbk" o encoding="locale"
Un proyecto uv nuevo aparece en 3.15 sin esperarlouv 0.13 cambió el valor por defectouv python pin 3.14
SyntaxWarning: 'return' in a 'finally' block desde una dependenciaLa librería tiene código antiguo que el Python nuevo señalaInofensivo; 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