Python 3.12 y 3.13: f-strings mejoradas, type aliases, @override y novedades clave

Python lanza versiones menores cada año. Python 3.12 (octubre 2023) y Python 3.13 (octubre 2024) introdujeron mejoras relevantes para el día a día: f-strings sin restricciones, alias de tipo con sintaxis propia, el decorador @override y generics sin TypeVar. Python 3.13 suma un REPL renovado, un JIT experimental y los primeros pasos hacia la eliminación opcional del GIL.

Python 3.12: f-strings sin restricciones

Hasta 3.11, las f-strings no podían contener backslashes ni comillas del mismo tipo que las exteriores dentro de las expresiones {}. Python 3.12 elimina esas limitaciones.

# Python 3.11: esto daba SyntaxError
# f"resultado: {'n'.join(nombres)}"  # backslash no permitido dentro de {}

# Python 3.12: funciona sin problemas
nombres = ["Ana", "Luis", "Marta"]
print(f"Lista:n{'n'.join(nombres)}")

# Comillas anidadas del mismo tipo
datos = {"clave": "valor"}
print(f"Valor: {datos["clave"]}")  # antes necesitabas cambiar las comillas externas

# Expresiones multi-línea dentro de f-strings
resultado = f"""
Suma: {
    sum(range(10))
}
"""
print(resultado.strip())  # Suma: 45

# Ahora puedes usar dict comprehensions dentro de f-strings
valores = [1, 2, 3, 4, 5]
print(f"Cuadrados: { {v: v**2 for v in valores} }")

Python 3.12: type alias con la sentencia type

# Antes de 3.12
from typing import TypeAlias
Vector: TypeAlias = list[float]
Matriz: TypeAlias = list[list[float]]

# Python 3.12+: sintaxis nativa
type Vector = list[float]
type Matriz = list[list[float]]
type Callback[T] = Callable[[T], None]  # alias genérico

def normalizar(v: Vector) -> Vector:
    modulo = sum(x**2 for x in v) ** 0.5
    return [x / modulo for x in v]

print(normalizar([3.0, 4.0]))  # [0.6, 0.8]

Python 3.12: generics sin TypeVar

# Antes de 3.12
from typing import TypeVar, Generic
T = TypeVar("T")

class Pila(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []
    def push(self, item: T) -> None:
        self._items.append(item)
    def pop(self) -> T:
        return self._items.pop()

# Python 3.12+: sintaxis con [T] directamente
class Pila[T]:
    def __init__(self) -> None:
        self._items: list[T] = []
    def push(self, item: T) -> None:
        self._items.append(item)
    def pop(self) -> T:
        return self._items.pop()

def primero[T](seq: list[T]) -> T:
    return seq[0]

pila: Pila[int] = Pila()
pila.push(42)
print(pila.pop())  # 42

Python 3.12: @override para herencia segura

from typing import override

class Animal:
    def hablar(self) -> str:
        return "..."

    def moverse(self) -> str:
        return "andando"

class Perro(Animal):
    @override
    def hablar(self) -> str:  # mypy/pyright verifican que esta firma existe en el padre
        return "Guau"

    @override
    def moverse(self) -> str:
        return "corriendo"

# Si renombras 'hablar' a 'hacer_ruido' en Animal sin actualizar Perro,
# @override provoca un error en el análisis estático

Python 3.13: REPL mejorado

El REPL de Python 3.13 incorpora edición multilínea, historial persistente, resaltado de sintaxis y autocompletado mejorado sin necesidad de ipython ni bpython.

# Nuevas opciones al lanzar el intérprete:
# python -c "import sys; print(sys.version)"  ?  3.13.x

# Dentro del REPL:
# - Edición de bloques multilínea con flechas
# - Ctrl+F para búsqueda en historial
# - Coloreado de errores (tracebacks en color por defecto)
# - help() integrado con paginación

# Ejemplo: puedes escribir y editar una función completa
def saludar(nombre):
    return f"Hola, {nombre}"

Python 3.13: JIT experimental y free-threaded mode

# JIT (compilador just-in-time) — activar en tiempo de compilación de CPython
# Compilar Python con --enable-experimental-jit
# Mejora de rendimiento: 5-15% en benchmarks típicos (varía mucho por workload)

# Free-threaded CPython (PEP 703): sin GIL
# Compilar con --disable-gil (Python 3.13t)
# Permite que múltiples threads corran en paralelo real en CPU-bound
# Estado: experimental, algunas extensiones C no son compatibles todavía

import sys
print(sys._is_gil_enabled())  # True (normal) o False (free-threaded build)

# En Python 3.13t (free-threaded):
import threading

resultados = []
def calcular(n):
    resultados.append(sum(range(n)))

threads = [threading.Thread(target=calcular, args=(1_000_000,)) for _ in range(4)]
for t in threads: t.start()
for t in threads: t.join()
print(len(resultados))  # 4 — paralelo real en free-threaded

Resumen de novedades por versión

  • 3.12: f-strings sin límites, type alias, generics con [T], @override, mejor rendimiento del intérprete (+5%).
  • 3.13: REPL reescrito, JIT experimental, free-threaded CPython (sin GIL opcional), locals() con semántica mejorada, deprecaciones limpiadas.
  • Migración: python -W error::DeprecationWarning mi_script.py para detectar código que dejará de funcionar.
# Comprobar la versión en tiempo de ejecución
import sys

if sys.version_info >= (3, 12):
    type Vector = list[float]  # sintaxis 3.12+
else:
    from typing import TypeAlias
    Vector: TypeAlias = list[float]

print(f"Python {sys.version_info.major}.{sys.version_info.minor}")

La recomendación práctica: si empiezas un proyecto nuevo, usa Python 3.12 como mínimo para aprovechar los generics simplificados y las f-strings sin restricciones. Si tu entorno de producción todavía no soporta 3.12, from __future__ import annotations aplaza la evaluación de type hints y te da compatibilidad hacia atrás.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP