Regístrate para acceder a más de 15 cursos gratuitos de programación con un simulador

Polimorfismo (tipado pato) Python: Polimorfismo

A medida que aprendemos Python, nos encontramos con objetos de diferentes clases que comparten comportamientos similares. Por ejemplo, tanto Article como Topic permiten añadir y obtener comentarios, pero usan métodos distintos. ¿Cómo podemos hacer que una función trabaje con ambos sin complicarnos?

La solución es la duck typing (tipado pato): una técnica elegante que permite trabajar con objetos sin preocuparse por su tipo exacto. En esta lección, veremos cómo aplicarla en Python.

¿Cuál es el problema?

Pensemos en este caso: necesitamos una función has_comments() que diga si un objeto (ya sea un artículo o un tópico) tiene comentarios.

Una solución puede ser así:

def has_comments(commentable):
    if isinstance(commentable, Article):
        return len(commentable.get_article_comments()) > 0
    elif isinstance(commentable, Topic):
        return len(commentable.get_topic_comments()) > 0

Y los métodos usados en cada clase serían:

class Article:
    def get_article_comments(self):
        return self.comments

class Topic:
    def get_topic_comments(self):
        return self.comments

Pero este enfoque tiene un problema importante: si luego añadimos otro tipo de objeto (digamos, Post), debemos volver y modificar la función has_comments() otra vez. El código se vuelve más difícil de mantener y entender con el tiempo.

Aquí es cuando entra el duck typing, una forma de pensar típica en Python.

¿Qué es el duck typing?

Una expresión muy común en programación es:

🦆 Si algo camina como pato, nada como pato y suena como pato, probablemente es un pato.

Esto traduce a código como: si un objeto tiene el comportamiento que necesitamos (por ejemplo, un método get_comments()), entonces podemos usarlo sin importar su clase o tipo exacto.

En lugar de preguntar de qué clase es un objeto (usando isinstance), simplemente probamos si el objeto se comporta como esperamos. Lo único que nos interesa es que tenga el método y funcione.


Hacer nuestro código más limpio con duck typing

Rediseñemos nuestras clases para que compartan los mismos métodos clave: add_comment() y get_comments().

class Article:
    def __init__(self):
        self.comments = []

    def add_comment(self, comment):
        self.comments.append(comment)

    def get_comments(self):
        return self.comments

class Topic:
    def __init__(self):
        self.comments = []

    def add_comment(self, comment):
        self.comments.append(comment)

    def get_comments(self):
        return self.comments

Aquí ambas clases tienen un comportamiento común: permitir almacenar y obtener comentarios.

Ahora sí, podemos escribir una única función que funcione con ambas:

def has_comments(item):
    # Aquí confiamos en que el objeto tiene un método llamado get_comments
    return len(item.get_comments()) > 0

¿Vemos la diferencia? No preguntamos si el objeto es un Article o un Topic, simplemente asumimos que se comporta como cualquier cosa que tenga el método get_comments().

Probémoslo en acción

article = Article()
topic = Topic()

print(has_comments(article))  # False: no hay comentarios
article.add_comment("Buena explicación!")
print(has_comments(article))  # True: ya tiene un comentario

print(has_comments(topic))    # False
topic.add_comment("Buen tema!")
print(has_comments(topic))    # True

¡Y funciona perfectamente para ambos!


¿Qué es el polimorfismo?

Hasta ahora hemos aplicado algo que en programación se llama polimorfismo. Es una forma de que una misma función, como has_comments(), trabaje con diferentes tipos de objetos.

Hay dos tipos principales de polimorfismo:

Tipo de Polimorfismo ¿Qué hace? Ejemplo
Polimorfismo de subtipos Funciona con diferentes objetos que comparten una interfaz común (como get_comments()) Hemos usado este tipo con Article y Topic
Polimorfismo paramétrico Usamos tipos genéricos que sirven para muchos tipos de datos (por ejemplo, listas de int, str) Usado con estructuras como list[T]

En Python, no necesitamos herencia para lograr polimorfismo gracias a su tipo dinámico. Nos basta con que los objetos tengan el comportamiento esperado.


¿Por qué evitar condiciones como isinstance?

Porque hacen que el código sea:

❌ Más difícil de extender

❌ Más difícil de leer

❌ Más propenso a errores

En cambio, si usamos duck typing, logramos que nuestro código se enfoque en lo que hacen los objetos, no en lo que son.


¿Y si el método no existe?

Es cierto, puede fallar si el objeto no tiene ese método. Para manejarlo, podemos usar hasattr() o capturar una excepción. Pero lo más común es confiar en que los objetos que usamos sí implementan lo que prometen. Si todos siguen el mismo contrato (tener get_comments()), no hay problema.



Resumen

  • Podemos escribir funciones que trabajen con diferentes tipos de objetos si ellos tienen los mismos métodos.
  • No necesitamos usar if isinstance(...); basta con asumir que un objeto se comporta como necesitamos.
  • El polimorfismo de subtipos nos permite tratar objetos distintos como si fueran iguales, siempre que compartan comportamiento.
  • El polimorfismo paramétrico aplica cuando escribimos lógica genérica independiente del tipo de los elementos.

Para acceder completo a curso necesitas un plan básico

El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.

Obtener acceso
130
cursos
1000
ejercicios
2000+
horas de teoría
3200
test

Obtén acceso

Cursos de programación para principiantes y desarrolladores experimentados. Comienza tu aprendizaje de forma gratuita

  • 130 cursos, 2000+ horas de teoría
  • 1000 ejercicios prácticos en el navegador
  • 360 000 estudiantes
Al enviar el formulario, aceptas el «Política de privacidad» y los términos de la «Oferta», y también aceptas los «Términos y condiciones de uso»

Nuestros graduados trabajan en empresas como:

Bookmate
Health Samurai
Dualboot
ABBYY