Lección 0.2.1 · 35 min
Instalación de Python con uv: versiones y ciclo de soporte
Python no es uno: hay una versión nueva cada octubre y cada una vive cinco años. Esta lección instala la del curso con uv, explica qué significa que una versión esté «en soporte» y enseña a comprobar desde el propio código con qué intérprete se ejecuta.
- Módulo
- 0.2 · Entorno de trabajo moderno
- Duración
- 35 min
Lecciones del nivel 0
0.1 · Bienvenida y expectativas
0.2 · Entorno de trabajo moderno
- 0.2.1 Instalación de Python con uv: versiones y ciclo de soporte
- 0.2.2 Entornos virtuales y dependencias: uv init, uv add, pyproject.toml y lockfiles
- 0.2.3 Editores (VS Code, Cursor, PyCharm) y notebooks (Jupyter, JupyterLab, marimo)
- 0.2.4 Terminal básica, rutas, variables de entorno y ficheros .env
- 0.2.5 Git y GitHub: commits, ramas, pull requests y .gitignore
- 0.2.6 Introducción a los asistentes de código con IA: prompts, revisión y tests
0.3 · Fundamentos del lenguaje
- 0.3.1 Variables, tipos y operadores; coma flotante y decimal para precios y ticks
- 0.3.2 Cadenas, f-strings y formato de números y fechas
- 0.3.3 Listas, tuplas, diccionarios, conjuntos y comprensiones
- 0.3.4 Control de flujo: if, elif, else, for, while y match-case
- 0.3.5 Funciones: argumentos, *args y **kwargs, lambdas y ámbito
- 0.3.6 Excepciones; módulos y paquetes, con los imports perezosos de Python 3.15
0.4 · Python intermedio
- 0.4.1 Programación orientada a objetos: clases, herencia, composición y dataclasses
- 0.4.2 Tipado: type hints, mypy o ty y Pydantic para configuraciones
- 0.4.3 Iteradores, generadores, decoradores y context managers
- 0.4.4 Ficheros (CSV, JSON, YAML, TOML) y fechas con zonas horarias
- 0.4.5 Logging profesional y testing con pytest
- 0.4.6 Concurrencia: threading, multiprocessing, asyncio y free-threading
0.5 · Computación numérica y datos
- 0.5.1 NumPy 2: arrays, broadcasting, vectorización, álgebra lineal y generadores aleatorios
- 0.5.2 pandas 3.0: Series, DataFrame, índices temporales, Copy-on-Write, tipo str y pd.col()
- 0.5.3 Selección, filtrado, groupby, merge, pivot, resample y ventanas móviles
- 0.5.4 Polars: API lazy frente a eager, expresiones, rendimiento y cuándo elegirlo frente a pandas
- 0.5.5 DuckDB y SQL esencial: SELECT, JOIN, GROUP BY y funciones de ventana sobre Parquet
0.6 · Visualización
0.7 · Matemáticas y estadística mínimas
Por qué importa la versión
Un programa de Python no se ejecuta solo: lo ejecuta un intérprete, el programa python que lee tu código y lo
convierte en operaciones. Cada versión del intérprete añade funciones al lenguaje, cambia detalles de la biblioteca
estándar y, con el tiempo, deja de recibir arreglos. Las librerías del curso (NumPy, pandas, Polars…) publican
paquetes para unas versiones concretas y abandonan las antiguas.
Para quien hace trading sistemático, esto tiene tres consecuencias prácticas:
- Reproducibilidad. Un backtest debe dar el mismo resultado hoy y dentro de un año. Si el intérprete o una librería cambian, un cálculo puede cambiar con ellos: un valor por defecto distinto, un redondeo, un aviso que antes no salía.
- Seguridad. Un sistema en real se conecta a un bróker con claves de API. Si su intérprete ya no recibe parches de seguridad, cualquier fallo que se descubra quedará abierto para siempre.
- Compatibilidad. Lo nuevo de las librerías llega primero a las versiones recientes. Quedarse en una versión antigua acaba dejando fuera de las mejoras de pandas 3.0 o NumPy 2 (módulo 0.5).
El curso usa Python 3.14 (en concreto 3.14.8, la versión con la que se ha ejecutado todo el código que verás). 3.13 también sirve. Esta lección explica por qué y cómo instalarla.
El ciclo de vida de una versión
Desde 2019, Python publica una versión nueva cada año, en octubre (PEP 602). Cada versión pasa por cinco fases, que la guía de desarrollo de Python describe así1Nota 1 · Python Developer's Guide, «Status of Python versions» (devguide.python.org/versions), consultada el 21 de octubre de 2026. Las fechas de fin de soporte desde 3.11 son previstas y las ajustan los responsables de cada versión.:
Fuente Mermaid
stateDiagram-v2 [*] --> feature feature --> prerelease: primera beta prerelease --> bugfix: versión final bugfix --> security: a los dos años security --> eol: a los cinco años eol --> [*]
- feature y prerelease: la versión está en desarrollo. Las betas y candidatas sirven para probar librerías, no para trabajar.
- bugfix: la versión ya es estable. Recibe arreglos de errores y de seguridad, con instaladores nuevos aproximadamente cada dos meses (3.14.1, 3.14.2…). Dura unos dos años desde 3.13; en las anteriores, 18 meses.
- security: solo parches de seguridad, publicados como código fuente y sin instaladores.
- end-of-life (eol): a los cinco años de la publicación, el soporte termina. El intérprete sigue funcionando, pero nadie lo arregla.
La figura de la cabecera dibuja ese ciclo para las versiones de 3.10 a 3.15, con una línea en octubre de 2026. La barra gruesa es la fase de correcciones; la fina, la de solo seguridad. Las fechas, de la guía de desarrollo:
| Versión | Publicada | Fase en octubre de 2026 | Fin de soporte |
|---|---|---|---|
| 3.10 | 4 oct 2021 | Fin de soporte | 1 oct 2026 |
| 3.11 | 24 oct 2022 | Solo seguridad | oct 2027 (previsto) |
| 3.12 | 2 oct 2023 | Solo seguridad | oct 2028 (previsto) |
| 3.13 | 7 oct 2024 | Solo seguridad | oct 2029 (previsto) |
| 3.14 | 7 oct 2025 | Correcciones | oct 2030 (previsto) |
| 3.15 | 9 oct 2026 | Correcciones | oct 2031 (previsto) |
Dos fechas de este mes cambian el mapa. El 1 de octubre de 2026, Python 3.10 llegó al final de su soporte: si algún servidor o tutorial antiguo lo usa, es momento de migrar. El 9 de octubre se publicó Python 3.15.02Nota 2 · Notas de la versión de Python 3.15.0, python.org, 9 de octubre de 2026., que entre otras novedades usa UTF-8 como codificación por defecto e introduce los imports perezosos explícitos (lección 0.3.6).
Instalar uv y Python
uv es un gestor de proyectos y paquetes de Python escrito en Rust por Astral. Sustituye a varias herramientas clásicas (pip, venv, pyenv, pip-tools) con una sola, mucho más rápida. En este curso hace dos cosas: instalar versiones de Python (esta lección) y gestionar los entornos y las dependencias de cada proyecto (lección 0.2.2).
Se instala con un script oficial. En Linux y macOS, desde la terminal (la terminal se ve con más calma en la lección 0.2.4; por ahora basta con copiar y pegar):
curl -LsSf https://astral.sh/uv/install.sh | shEn Windows, desde PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"Si prefieres un gestor de paquetes del sistema, también vale brew install uv (macOS) o
winget install --id=astral-sh.uv -e (Windows). Cierra y vuelve a abrir la terminal y comprueba que responde:
uv --versionCon uv instalado, instalar Python es un comando:
uv python install 3.14 # la última 3.14.x
uv python list # versiones instaladas y disponibles
python3.14 --version # uv deja un ejecutable con la versión
uv python upgrade 3.14 # pasar a la última 3.14.x más adelanteuv descarga una distribución de Python ya compilada y la guarda en su propia carpeta. No sobrescribe nada:
- Linux: la distribución trae su propio Python, que usan herramientas del sistema. No lo actualices ni instales
paquetes en él con
sudo pip; un cambio ahí puede romper el gestor de paquetes del sistema. - macOS: puede haber un
python3de las herramientas de Xcode, normalmente antiguo. Déjalo estar. - Windows: no hace falta el instalador de python.org ni la tienda de Microsoft si usas uv.
Tampoco hace falta instalar Python a mano antes de empezar un proyecto: si un proyecto pide 3.14 y no la tienes, uv la
descarga al ejecutar el primer comando. En la práctica casi nunca llamarás a python directamente, sino a
uv run python dentro de un proyecto, que elige la versión correcta por ti (lección 0.2.2).
Para fijar la versión de una carpeta, uv python pin 3.14 crea en ella un fichero .python-version con el número.
uv lo lee cada vez que trabajas en esa carpeta, y otras herramientas también lo entienden. El proyecto del curso lo
tendrá desde el primer momento (lección 0.2.2).
Comprobar el intérprete desde Python
Instalar es la mitad. La otra mitad es saber, desde el propio código, con qué intérprete se está ejecutando: en tu
portátil, en un servidor o en el ordenador de otra persona. El módulo sys de la biblioteca estándar lo dice:
import sys
sys.version_infosys.version_info(major=3, minor=14, micro=8, releaselevel='final', serial=0)sys.version_info es una tupla con nombre: versión mayor, menor y de corrección (micro), y el nivel de la versión
(final en una versión estable; alpha, beta o candidate en una de prueba). Al ser una tupla, se puede comparar
con otra tupla:
print(sys.version_info[:2])
print(sys.version_info >= (3, 13))
print(sys.version_info >= (3, 15))(3, 14)
True
FalseEl módulo platform añade el resto: la versión como texto, la implementación (CPython es la de referencia, la que
instala uv) y el sistema operativo y la arquitectura de la máquina. En Linux, platform.system() devuelve Linux; en
macOS, Darwin; en Windows, Windows. La salida de abajo es la de la máquina donde se ejecutó el curso:
import platform
print("Python:", platform.python_version())
print("Implementación:", platform.python_implementation())
print("Sistema:", platform.system(), platform.machine())Python: 3.14.8
Implementación: CPython
Sistema: Linux x86_64Versiones como tuplas, no como texto
Un error clásico al trabajar con versiones es compararlas como cadenas de texto. Python compara las cadenas carácter a carácter, y el carácter «1» va antes que el «9»:
versiones = ["3.9", "3.10", "3.14", "3.13"]
print(sorted(versiones))
print("3.9" > "3.10")['3.10', '3.13', '3.14', '3.9']
TrueSegún el texto, 3.9 es más moderna que 3.10. Es el mismo problema que ordenar fechas escritas como «9/3/2025» o importes guardados como texto: el orden parece razonable hasta que deja de serlo. La solución es convertir cada versión en una tupla de enteros antes de compararla:
def como_tupla(version: str) -> tuple[int, ...]:
"""'3.10' -> (3, 10)"""
return tuple(int(parte) for parte in version.split("."))
print(sorted(versiones, key=como_tupla))
print(como_tupla("3.9") > como_tupla("3.10"))
print(max(versiones, key=como_tupla))['3.9', '3.10', '3.13', '3.14']
False
3.14Las tuplas se comparan elemento a elemento: primero el 3 con el 3 y, como empatan, el 9 con el 10, esta vez como
números. Por eso sys.version_info es una tupla y no un texto. La biblioteca packaging, que usan pip y uv por
dentro, hace lo mismo con versiones más complejas («2.5.4», «3.0.0rc1»), pero para comparar versiones de Python basta
con la tupla.
Qué versiones tienen soporte hoy
Con la tabla de antes se puede calcular cuántos meses de soporte le quedan a cada versión en una fecha dada. Se usa una fecha fija (21 de octubre de 2026) para que el resultado no cambie según el día en que ejecutes la celda; los fines de soporte de la guía de desarrollo vienen como año y mes:
fin_soporte = {
"3.10": (2026, 10), "3.11": (2027, 10), "3.12": (2028, 10),
"3.13": (2029, 10), "3.14": (2030, 10), "3.15": (2031, 10),
}
hoy = (2026, 10)
for version, (anio, mes) in fin_soporte.items():
meses = (anio - hoy[0]) * 12 + (mes - hoy[1])
estado = "sin soporte" if meses <= 0 else f"{meses} meses"
print(f"Python {version:>5}: {estado}")Python 3.10: sin soporte
Python 3.11: 12 meses
Python 3.12: 24 meses
Python 3.13: 36 meses
Python 3.14: 48 meses
Python 3.15: 60 mesesPara un proyecto nuevo, la regla práctica: la versión más reciente con al menos unos meses de rodaje y todas las librerías disponibles. Para un sistema en real, además, una versión a la que le queden años de soporte, porque migrar un sistema que opera cuesta más que migrar un notebook.
La versión, junto a los resultados
Un backtest produce números: rentabilidad, volatilidad, drawdown. Esos números dependen de los datos, del código y
del entorno. El código lo guardará Git (lección 0.2.5) y los datos, tu carpeta datos/; el entorno hay que anotarlo.
Un diccionario con las versiones, guardado junto a cada resultado, basta para empezar:
import json
import numpy as np
import pandas as pd
entorno = {
"python": platform.python_version(),
"implementacion": platform.python_implementation(),
"sistema": platform.system(),
"numpy": np.__version__,
"pandas": pd.__version__,
}
print(json.dumps(entorno, indent=2)){
"python": "3.14.8",
"implementacion": "CPython",
"sistema": "Linux",
"numpy": "2.5.4",
"pandas": "3.0.6"
}Si dentro de seis meses el mismo backtest da otro Sharpe, lo primero es comparar este bloque con el actual. La lección
0.2.2 va un paso más allá: fija las versiones exactas de todas las librerías en un fichero (uv.lock) para que el
entorno sea idéntico en cualquier máquina.
Ejercicios
- Instala uv y Python 3.14 en tu ordenador. Ejecuta
uv python listy anota qué versiones de Python tenías ya instaladas antes (las del sistema) y dónde están.
Solución
La salida depende de tu máquina. En Linux suele aparecer el Python del sistema en /usr/bin/python3 (la versión que
traiga tu distribución) y la 3.14 de uv en una carpeta de tu usuario. En macOS puede aparecer el python3 de las
herramientas de Xcode y, si usas Homebrew, el suyo. En Windows, solo las que hayas instalado tú. Lo importante: el
Python del sistema sigue ahí y no lo has tocado.
- Escribe una función
exigir_python(minima)que reciba una tupla como(3, 13)y lance unRuntimeErrorcon un mensaje claro si el intérprete es más antiguo. ¿Dónde la llamarías en un sistema que opera en real?
Solución
def exigir_python(minima: tuple[int, int]) -> None:
actual = sys.version_info[:2]
if actual < minima:
raise RuntimeError(
f"Se necesita Python {minima[0]}.{minima[1]} o superior; "
f"este es {actual[0]}.{actual[1]}"
)
exigir_python((3, 13))
print("Versión correcta")Versión correctaAl principio del programa, antes de conectar con el bróker o de cargar datos: es mejor que el sistema no arranque a que arranque con un intérprete en el que nadie lo ha probado. Las excepciones se ven en la lección 0.3.6.
- Amplía la celda de los metadatos del entorno con la fecha y hora de ejecución en UTC y guárdala en un fichero
entorno.json. ¿Por qué en UTC y no en la hora local?
Solución
from datetime import datetime, timezone
from pathlib import Path
entorno["ejecutado_utc"] = datetime(2026, 10, 21, 16, 30,
tzinfo=timezone.utc).isoformat()
Path("entorno.json").write_text(json.dumps(entorno, indent=2))
print(json.loads(Path("entorno.json").read_text())["ejecutado_utc"])2026-10-21T16:30:00+00:00En tu código usarías datetime.now(timezone.utc); aquí la fecha es fija para que la salida sea siempre la misma. UTC
porque es la misma en todas las máquinas y no tiene cambios de horario: un servidor en Fráncfort, otro en Virginia y
tu portátil escriben la misma hora para el mismo instante. Las zonas horarias de los mercados se ven en la lección
0.4.4.
Footnotes
-
Python Developer's Guide, «Status of Python versions» (devguide.python.org/versions), consultada el 21 de octubre de 2026. Las fechas de fin de soporte desde 3.11 son previstas y las ajustan los responsables de cada versión. ↩
-
Notas de la versión de Python 3.15.0, python.org, 9 de octubre de 2026. ↩
Respuesta plegada en cada pregunta
Autoevaluación
Un servidor que ejecuta tu sistema en real tiene Python 3.10. ¿Qué ha cambiado desde el 1 de octubre de 2026?
- ANada: el código sigue funcionando y seguirá recibiendo parches
- BPython 3.10 ha dejado de recibir correcciones, incluidas las de seguridad
- CPython 3.10 deja de funcionar en Linux
- Dpip ya no puede instalar paquetes en 3.10
Ver respuesta
Respuesta B. Python 3.10 ha dejado de recibir correcciones, incluidas las de seguridad
El fin de soporte no apaga nada: el intérprete sigue funcionando. Lo que se acaba son los parches, también los de seguridad, y poco a poco las librerías dejan de publicar versiones para él. Un sistema en real no debería depender de una versión sin soporte.
¿Qué devuelve
sorted(["3.9", "3.10", "3.14"])?- A
['3.9', '3.10', '3.14'] - B
['3.10', '3.14', '3.9'] - C
['3.14', '3.10', '3.9'] - DUn error, porque no son números
Ver respuesta
Respuesta B.
['3.10', '3.14', '3.9']Las cadenas se comparan carácter a carácter: «1» va antes que «9», así que «3.10» y «3.14» van antes que «3.9». Las versiones se comparan como tuplas de enteros, como
sys.version_info.- A
¿En qué fase está Python 3.14 en octubre de 2026?
- ADesarrollo (feature)
- BCorrecciones (bugfix): recibe arreglos de errores y de seguridad, con instaladores cada dos meses aproximadamente
- CSolo seguridad
- DFin de soporte
Ver respuesta
Respuesta B. Correcciones (bugfix): recibe arreglos de errores y de seguridad, con instaladores cada dos meses aproximadamente
Se publicó el 7 de octubre de 2025 y las versiones desde la 3.13 tienen unos dos años de correcciones. Pasará a solo seguridad en torno a octubre de 2027 y su soporte termina en octubre de 2030.
¿Por qué conviene guardar la versión de Python, NumPy y pandas junto a los resultados de un backtest?
- APorque lo exige la normativa
- BPara poder reproducir el resultado: un cambio de versión puede cambiar un cálculo, un valor por defecto o el rendimiento
- CPara que el backtest vaya más rápido
- DNo sirve para nada si el código está en Git
Ver respuesta
Respuesta B. Para poder reproducir el resultado: un cambio de versión puede cambiar un cálculo, un valor por defecto o el rendimiento
Git guarda el código, no el intérprete ni las librerías. Si un resultado cambia al repetirlo meses después, la primera pregunta es si cambió el entorno. La lección 0.2.2 resuelve el problema de raíz con un lockfile.
Ideas clave
- Cada octubre sale una versión de Python. Tiene unos dos años de correcciones, después solo parches de seguridad, y su soporte termina a los cinco años.
- En octubre de 2026: 3.10 sin soporte desde el día 1, 3.15 publicada el día 9; el curso usa 3.14 y 3.13 también sirve.
- uv instala y gestiona versiones de Python sin tocar el Python del sistema:
uv python install 3.14. sys.version_infoes una tupla: compárala con(3, 13), nunca compares versiones como texto.- Un resultado de backtest sin la versión del entorno no es reproducible: guárdala junto a los números.