typing.override: valida sobrescrituras de métodos

Publicado el: 05/09/2026
Tempo de leitura: 6 minutos
Desarrollador revisando código Python y métodos sobrescritos

El decorador typing.override permite declarar de forma explícita que un método de una subclase reemplaza un método definido en una clase base. Está disponible en la biblioteca estándar desde Python 3.12 y no modifica el despacho normal en tiempo de ejecución. Su utilidad principal aparece en el análisis estático, las revisiones de código y el mantenimiento seguro de jerarquías orientadas a objetos.

En un programa pequeño, una sobrescritura puede parecer evidente. En una base de código grande, un cambio de nombre, un error tipográfico o una firma incompatible pueden convertir silenciosamente una sobrescritura en un método nuevo que nadie llama. El programa puede seguir ejecutándose, pero perder el comportamiento polimórfico esperado. Con @override, analizadores como Pyright, mypy e IDEs modernas pueden comprobar esa intención.

Ejemplo básico

from typing import override

class Notificador:
    def enviar(self, mensaje: str) -> None:
        print(mensaje)

class NotificadorEmail(Notificador):
    @override
    def enviar(self, mensaje: str) -> None:
        print(f"Email: {mensaje}")

El decorador indica que enviar debe existir en algún ancestro. Si la subclase escribe accidentalmente enviar_mensaje o comete un error en el nombre, el analizador puede informar que no existe un miembro heredado correspondiente. Sin la marca, ese error sería simplemente un método nuevo válido.

Ventajas de typing.override

La primera ventaja es la documentación verificable. Quien lee la clase sabe de inmediato que el método forma parte de un contrato heredado. No necesita recorrer toda la jerarquía para descubrir la intención.

La segunda ventaja es la seguridad en refactorizaciones. Si el método base cambia de nombre, las implementaciones marcadas dejan diagnósticos claros. El equipo encuentra los puntos afectados antes de desplegar el cambio.

La tercera ventaja es la comprobación de firmas. Las herramientas pueden comparar parámetros, valores opcionales, tipos de retorno y sobrecargas. Una sobrescritura incompatible se detecta antes de convertirse en un fallo de producción.

Firmas compatibles

Una subclase debe poder utilizarse donde se espera la clase base. Por eso, restringir un parámetro aceptado suele romper el contrato.

from typing import override

class Repositorio:
    def guardar(self, dato: object) -> bool:
        return True

class RepositorioTexto(Repositorio):
    @override
    def guardar(self, dato: str) -> bool:
        return bool(dato)

La clase base acepta cualquier objeto, mientras que la subclase acepta solamente cadenas. Código tipado como Repositorio podría llamar guardar(123). La implementación concreta no cumpliría esa promesa, de modo que un analizador puede rechazarla.

El retorno, en cambio, puede ser más específico en muchos casos. Si el método base devuelve Animal, la subclase puede devolver Perro cuando Perro es un subtipo de Animal.

Clases base abstractas

@override combina muy bien con abc.ABC y @abstractmethod. El método abstracto define la obligación y el decorador muestra que la implementación concreta cumple deliberadamente ese contrato.

from abc import ABC, abstractmethod
from typing import override

class Conversor(ABC):
    @abstractmethod
    def convertir(self, valor: str) -> int:
        raise NotImplementedError

class ConversorDecimal(Conversor):
    @override
    def convertir(self, valor: str) -> int:
        return int(valor, 10)

Esta combinación mejora la legibilidad de frameworks, adaptadores, repositorios y sistemas de plugins.

Properties, classmethods y staticmethods

También es posible sobrescribir propiedades, métodos de clase y métodos estáticos. El orden de los decoradores importa porque cada decorador recibe el resultado del que aparece debajo.

from typing import override

class Documento:
    @property
    def formato(self) -> str:
        return "genérico"

class PDF(Documento):
    @property
    @override
    def formato(self) -> str:
        return "pdf"

Colocar @override cerca de la función subyacente suele ofrecer la información más clara al analizador. El soporte para descriptores complejos puede variar, por lo que conviene mantener actualizadas las herramientas.

Herencia múltiple y super

En herencia múltiple, el decorador confirma que existe un miembro compatible en la ascendencia, pero no decide cuál se ejecuta. La resolución depende de la MRO de Python.

class Registrable:
    def ejecutar(self) -> None:
        print("registro")

class Auditable:
    def ejecutar(self) -> None:
        print("auditoría")

class Servicio(Registrable, Auditable):
    @override
    def ejecutar(self) -> None:
        super().ejecutar()
        print("servicio")

super() sigue Servicio.__mro__. @override no cambia esa secuencia ni obliga a llamar al método padre.

Protocolos y tipado estructural

Un Protocol puede cumplirse sin herencia. Una clase puede tener todos los miembros requeridos y ser compatible estructuralmente. Si no existe una clase ancestral real, usar @override puede ser engañoso.

Utiliza protocolos para describir capacidades y @override para una relación nominal de herencia. Ambas técnicas pueden convivir, pero representan ideas distintas.

Compatibilidad con Python anterior

Los proyectos que todavía admiten Python 3.11 o versiones anteriores pueden importar el backport desde typing_extensions.

try:
    from typing import override
except ImportError:
    from typing_extensions import override

Una biblioteca puede importar siempre desde typing_extensions mientras mantenga soporte para intérpretes antiguos.

Comportamiento en ejecución

El decorador es principalmente una señal para herramientas de tipado. No impide por sí solo ejecutar una sobrescritura inválida y no sustituye un sistema de contratos. Algunas implementaciones pueden añadir un atributo como __override__, pero la lógica de la aplicación no debería depender de ese detalle.

Para obtener el beneficio real, ejecuta el analizador en integración continua y muestra sus diagnósticos en la IDE. Sin análisis estático, la marca sigue ayudando a lectores, pero pierde gran parte de su protección automática.

No reemplaza las pruebas

@override comprueba coherencia estructural, no la lógica de negocio. Un método puede tener la firma correcta y devolver un cálculo incorrecto, omitir un efecto lateral importante o llamar super() en un orden inadecuado.

Las pruebas deben invocar las implementaciones a través de la interfaz base. Así se comprueba que el polimorfismo funciona y que todas las subclases respetan el comportamiento observable.

Adopción en equipos

Empieza por puntos de extensión, servicios, adaptadores, repositorios, serializadores y sistemas con muchas implementaciones. Son las áreas donde una refactorización de la clase base puede causar más fallos silenciosos.

Algunos analizadores permiten exigir el decorador en toda sobrescritura. Activar esa regla aporta consistencia. En proyectos antiguos, conviene introducirla gradualmente para evitar una migración demasiado grande.

Errores frecuentes

No uses @override solo porque dos métodos comparten nombre; debe existir una relación de herencia. No supongas que el decorador corrige firmas incompatibles: únicamente permite detectarlas. Tampoco crees jerarquías profundas solo para usarlo; la composición puede ser más sencilla.

Revisa además si la implementación debe llamar a super(). Algunas sobrescrituras reemplazan por completo el comportamiento, mientras que la herencia cooperativa necesita que cada clase continúe la cadena. El decorador no puede decidir cuál diseño corresponde.

Recursos relacionados

Consulta también nuestras guías sobre inspect en Python, dataclass_transform, TypeVarTuple y StrEnum. Como referencias externas, revisa la documentación oficial de typing.override y la PEP 698.

Conclusión

typing.override es una anotación pequeña con un gran valor de mantenimiento. Hace visible la intención heredada, detecta miembros renombrados o mal escritos, mejora la validación de firmas y convierte refactorizaciones arriesgadas en diagnósticos claros. Junto con análisis estático y pruebas, permite evolucionar jerarquías de clases con más seguridad.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador trabajando con colas e hilos en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    queue.SimpleQueue: cola FIFO segura entre hilos

    Aprende queue.SimpleQueue en Python para crear colas FIFO seguras entre hilos, workers y diseños productor-consumidor.

    Ler mais

    Tempo de leitura: 5 minutos
    04/09/2026
    Desarrollador trabajando con enums y código Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    StrEnum en Python: enums como strings

    Aprende StrEnum en Python para crear enums como strings, validar entradas, serializar JSON y organizar APIs y configuraciones.

    Ler mais

    Tempo de leitura: 5 minutos
    04/09/2026
    Carpetas y directorios para contextlib.chdir en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: restaura directorios automáticamente

    Aprende contextlib.chdir en Python para cambiar directorios temporalmente, restaurar rutas y crear pruebas confiables sin errores de estado global.

    Ler mais

    Tempo de leitura: 6 minutos
    03/09/2026
    Monitoreo de rendimiento y ejecución de código Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sys.monitoring: instrumentación de bajo overhead

    Aprende sys.monitoring en Python para instrumentar ejecución con bajo overhead, eventos selectivos, callbacks y observabilidad segura.

    Ler mais

    Tempo de leitura: 6 minutos
    03/09/2026
    Desarrollador organizando datos con operator.attrgetter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    operator.attrgetter: ordena objetos por atributos

    Aprende operator.attrgetter en Python para ordenar, agrupar y transformar objetos por atributos simples o anidados con código claro.

    Ler mais

    Tempo de leitura: 4 minutos
    02/09/2026
    Programación asíncrona con asyncio.Runner en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    asyncio.Runner: reutiliza el event loop con seguridad

    Aprende asyncio.Runner en Python para reutilizar el event loop, controlar contexto, señales, debug, cancelación y cierre asíncrono seguro.

    Ler mais

    Tempo de leitura: 7 minutos
    02/09/2026