Últimas novedades de Python

Últimas novedades de Python

Este artículo explica las características más recientes de Python.

Explicaremos paso a paso las características más destacadas de las versiones de Python 3.12 a 3.13 desde una perspectiva práctica de aplicaciones 'utilizables de inmediato'.

YouTube Video

Últimas novedades de Python

En los últimos años, Python ha evolucionado haciendo énfasis no solo en la 'facilidad de escritura', sino también en la 'robustez, velocidad y legibilidad'. A continuación, presentamos las características más destacadas de las versiones de Python 3.12 a 3.13.

Mejoras dramáticas en los mensajes de error (Python 3.12)

En Python 3.12, los errores se muestran de manera más concreta y visual. Ahora es posible identificar al instante dónde se encuentran los errores y reducir significativamente el tiempo de depuración.

1def calc_total(price, tax):
2    return price + price * tax
3
4result = calc_total(100, )
  • Los argumentos faltantes se muestran con la línea y ubicación correspondiente, por lo que no te confundirás al identificar la causa.

Uso práctico de la sentencia 'match' (coincidencia de patrones estructurales)

La sentencia 'match' permite describir de forma declarativa ramas condicionales complejas y discriminar estructuras de datos. El manejo de diccionarios y estructuras anidadas se vuelve especialmente más legible.

1user = {"status": "active", "name": "Alice"}
2
3match user:
4    case {"status": "active", "name": name}:
5        print(f"Welcome back, {name}!")
6    case {"status": "inactive"}:
7        print("Please activate your account.")
8    case _:
9        print("Unknown user status.")
  • Como puedes realizar ramificaciones condicionales y extracción de datos simultáneamente, ya no es necesario anidar sentencias if.

Coincidencia de patrones intuitiva para manejar datos anidados

La sentencia 'match' también es efectiva para datos estructurados como JSON o respuestas de API.

1data = {"user": {"name": "Bob", "age": 25}}
2
3match data:
4    case {"user": {"name": name, "age": age}}:
5        print(f"{name} is {age} years old.")
  • Puedes extraer solo los elementos necesarios de manera segura, reduciendo la necesidad de código defensivo.

Salida de depuración mejorada de f-strings (notación =` / Python 3.8 y posteriores, usabilidad mejorada)

Con los f-strings ahora puedes añadir = para mostrar tanto la expresión como su resultado al mismo tiempo. Esta característica está especializada para la depuración y resulta muy útil cuando quieres comprobar rápidamente el contenido de una variable.

1x = 10
2y = 20
3print(f"{x=}, {y=}, {x+y=}")
  • Como los nombres y valores de las variables se muestran juntos, la depuración temporal usando sentencias print() es más fácil de leer.
  • Puedes escribir salidas de registro y código de verificación de manera más concisa y expresiva.

Anotaciones de tipo simplificadas y alias de tipo (Python 3.12: nueva sintaxis de alias de tipo)

En Python 3.12, se introdujo una sintaxis dedicada para definir alias de tipo: la instrucción type. Esto permite que las anotaciones de tipo funcionen no solo como información complementaria, sino también como un elemento del lenguaje que expresa claramente la intención de diseño.

1type UserId = int
2type UserName = str
3
4def greet(user_id: UserId, name: UserName) -> str:
5    return f"Hello, {name} (id={user_id})"
  • Al dar significado a UserId o UserName, se pueden diferenciar claramente los roles, incluso si ambos utilizan el mismo tipo int o str.
  • Las definiciones de tipo se vuelven más concisas, reduciendo el coste de comprensión durante la revisión y el mantenimiento del código.
  • Antes, los alias de tipo como UserId = int se creaban mediante asignación, pero al usar la instrucción type se hace explícito que 'esto es una definición de tipo'. Esto es especialmente eficaz para mejorar la legibilidad del diseño en bases de código medianas y grandes.

Anotaciones de tipo naturales usando tipos incorporados (genéricos simplificados desde Python 3.9+)

Desde Python 3.9, puedes usar tipos incorporados como list o dict directamente como genéricos.

Esto permite escribir anotaciones de tipo intuitivas y legibles sin importar tipos del módulo typing.

1def sum_numbers(numbers: list[int]) -> int:
2    return sum(numbers)
3
4print(sum_numbers([1, 2, 3, 4]))
  • Las anotaciones de tipo funcionan no como 'restricciones', sino como 'documentación que explica el contenido del procesamiento'.

Encadenamiento seguro de métodos con el tipo Self (Python 3.11 y posteriores)

Desde Python 3.11, puedes especificar Self como tipo de retorno para métodos que devuelven la propia clase.

Esto permite escribir código de encadenamiento de métodos de forma segura, sin perder información de tipo.

 1from typing import Self
 2
 3class Counter:
 4    def __init__(self, value: int = 0) -> None:
 5        self.value = value
 6
 7    def increment(self) -> Self:
 8        self.value += 1
 9        return self
10
11counter = Counter()
12counter.increment().increment()
13print(counter.value)
  • Incluso para métodos que devuelven self, se preserva el tipo de retorno correcto.
  • Los IDEs y comprobadores de tipos pueden comprender correctamente el encadenamiento de métodos.

Manipulación de cadenas más clara (removeprefix / removesuffix | Python 3.9 y posteriores)

Desde Python 3.9, se han añadido los métodos especializados str.removeprefix() y str.removesuffix() para eliminar de forma segura prefijos y sufijos en cadenas. Con estos métodos, puedes expresar con precisión la intención de 'eliminar solo el principio o el final' en tu código.

1filename = "report_2026.txt"
2
3clean_name = filename.removeprefix("report_")
4name_without_ext = clean_name.removesuffix(".txt")
5
6print(name_without_ext)
  • La cadena especificada se elimina solo si existe al principio o al final, evitando reemplazos no deseados.
  • Este enfoque aporta mayor legibilidad y seguridad que usar replace() o el corte de cadenas (slicing).
  • Especialmente al manejar 'cadenas con un formato definido', como nombres de archivos o preprocesamiento de URLs, el uso de estos métodos puede reducir drásticamente el riesgo de errores.

Comparación robusta de cadenas para internacionalización (str.casefold() | Soporte Unicode)

str.casefold() en Python es un método para comparación sin distinción de mayúsculas/minúsculas que tiene en cuenta Unicode. A diferencia de lower() o upper(), normaliza las cadenas, incluyendo la conversión de caracteres específica de cada idioma.

1text1 = "Stra\u00dfe"
2text2 = "strasse"
3
4print(text1)
5print(text2)
6
7print(f"Comparison Result: {text1.casefold() == text2.casefold()}")
  • Puede manejar correctamente diferencias dependientes del idioma, como el alemán ß y ss.
  • Esta es una técnica esencial para aplicaciones que requieren soporte multilingüe o internacionalización.

Soporte estándar de TOML (tomllib | Python 3.11 y posteriores)

Desde Python 3.11, el módulo tomllib para leer archivos de configuración TOML se ha incorporado a la biblioteca estándar. La gestión de configuraciones ahora puede realizarse completamente en Python, sin depender de bibliotecas externas.

 1import tomllib
 2
 3with open("config.toml", "rb") as f:
 4    config = tomllib.load(f)
 5
 6print(config["database"]["host"])
 7
 8# config.toml
 9# title = "TOML Example"
10# [database]
11# host = "192.168.1.1"
12# ports = [ 8001, 8001, 8002 ]
  • Ya no se necesitan paquetes externos como toml, lo que simplifica las dependencias.
  • La carga de archivos de configuración se ha estandarizado, facilitando la distribución, la operación y los entornos de integración continua (CI).

Gestión de excepciones para la era del procesamiento paralelo (ExceptionGroup / except* | Python 3.11 y posteriores)

Python 3.11 introdujo ExceptionGroup para manejar múltiples excepciones juntas y la sintaxis except* para gestionarlas de manera segura en diferentes ramificaciones. Esta nueva característica permite gestionar 'errores simultáneos' que aparecen en el procesamiento asíncrono o paralelo.

 1def process(values):
 2    errors = []
 3    for v in values:
 4        if v < 0:
 5            errors.append(ValueError(f"Negative value: {v}"))
 6    if errors:
 7        raise ExceptionGroup("Invalid values", errors)
 8
 9try:
10    process([1, -2, -3])
11except* ValueError as e:
12    print("Handled:", e)
  • Ahora se pueden lanzar y clasificar varias excepciones en una sola operación.
  • Resuelve el problema en el procesamiento asíncrono donde solo se podía ver el primer error.
  • En operaciones como asyncio.gather() o el procesamiento por lotes en paralelo, pueden producirse simultáneamente varios motivos de fallo. Al utilizar ExceptionGroup, es más sencillo organizar la recopilación de errores, el registro y las estrategias de reintento.

El rendimiento mejora simplemente actualizando a la versión más reciente

Desde Python 3.11, muchos procesos se han acelerado gracias a optimizaciones internas.

1def count_up(n):
2    total = 0
3    for i in range(n):
4        total += i
5    return total
6
7print(count_up(1_000_000))
  • Una gran ventaja es que la mejora de velocidad se consigue sin necesidad de reescribir el código.

Controlar la recolección de basura (gestión explícita mediante el módulo gc)

En Python, el uso del módulo estándar gc permite desactivar temporalmente o ejecutar manualmente la recolección de basura. Esta es una técnica de optimización eficaz en escenarios como el procesamiento por lotes de grandes volúmenes de datos u operaciones críticas de rendimiento.

1import gc
2
3gc.disable()
4# heavy batch processing
5gc.enable()
6gc.collect()
  • Suprimir activaciones innecesarias de la recolección de basura puede reducir las fluctuaciones en el tiempo de procesamiento.
  • Se puede recolectar explícitamente en intervalos del proceso, facilitando el seguimiento del uso de memoria.
  • Sin embargo, esta técnica no debe usarse como optimización por defecto, sino solo si el análisis de rendimiento indica que la GC es un cuello de botella. Para la mayoría de las aplicaciones, lo más seguro es confiar en la recolección automática de basura de Python.

Resumen

Con las mejoras en los mensajes de error y la evolución de las anotaciones de tipo en la generación de Python 3.12 a 3.13, entender y mantener el código es más fácil que nunca. Además, mejoras como una mejor experiencia de depuración y el aumento de rendimiento gracias a la optimización interna contribuyen directamente y de forma efectiva a la productividad. No es necesario utilizar todas estas novedades a la vez; es práctico comenzar con la versión más reciente de Python e ir incorporando las nuevas características poco a poco según sea necesario. Esta adopción progresiva conduce a un código Python más legible y robusto.

Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.

YouTube Video