Polmorfismo - DavSeb21031990/plan-estudio-python-go GitHub Wiki
La palabra "polimorfismo" tiene su origen en el griego y significa "muchas formas". En el contexto de la Programación Orientada a Objetos (POO), el polimorfismo es la capacidad inherente de los objetos de diferentes tipos de ser tratados como objetos de una superclase común. Esta característica permite que múltiples clases implementen el mismo método de maneras diversas, lo que es fundamental para lograr la abstracción y la encapsulación en los lenguajes de programación.
Cómo Funciona el Polimorfismo en Python
El polimorfismo opera estableciendo una relación entre clases mediante la herencia y la sobreescritura de métodos. Cuando una superclase define un método, sus subclases tienen la facultad de anular ese método para proporcionar su propia implementación específica. La clave del polimorfismo reside en que, en tiempo de ejecución, el método apropiado se invoca basándose en el tipo real del objeto, no en el tipo de la referencia que lo apunta. Este proceso se conoce como enlace dinámico o late binding.
Python, en particular, se beneficia del concepto de "Duck Typing". Esto significa que el polimorfismo en Python no se basa estrictamente en la herencia de clases, sino en la presencia de métodos con el mismo nombre. Si un objeto "camina como un pato y grazna como un pato, entonces es un pato", independientemente de su herencia explícita. Esto permite una gran flexibilidad, ya que cualquier objeto que implemente un método específico puede ser tratado polimórficamente, incluso si no comparte una clase base común.
Tipos de Polimorfismo
El polimorfismo se clasifica generalmente en dos tipos principales:
- Polimorfismo en Tiempo de Compilación (Estático o Early Binding):
Este tipo de polimorfismo se resuelve durante la fase de compilación del programa. Se logra principalmente a través de la sobrecarga de funciones (function overloading
) y la sobrecarga de operadores (operator overloading
).
Como se mencionó, Python no soporta la sobrecarga de funciones de la misma manera que Java o C++, pero sí permite la sobrecarga de operadores (por ejemplo, el operador + puede sumar números o concatenar cadenas) y el uso de parámetros con valores por defecto para simular la sobrecarga de funciones.
- Polimorfismo en Tiempo de Ejecución (Dinámico o Late Binding):
Este tipo de polimorfismo se resuelve durante la ejecución del programa. Se logra principalmente a través de la sobreescritura de métodos (function overriding) en el contexto de la herencia. En Python, la sobreescritura de métodos es dinámicamente enlazada por defecto, lo que significa que no se requiere una palabra clave especial como virtual
(como en C++
).
Beneficios del Polimorfismo
La aplicación del polimorfismo en la programación aporta múltiples ventajas:
-
Reutilización y Modularidad del Código: Permite que las clases compartan comportamientos comunes a través de la herencia, lo que reduce la duplicación de código y promueve un diseño modular.
-
Flexibilidad y Extensibilidad: Facilita la adición de nuevas subclases sin la necesidad de modificar el código existente. Esto mejora la adaptabilidad del sistema a futuros cambios y lo hace más fácil de extender.
-
Creación de Algoritmos Genéricos: Permite el desarrollo de algoritmos que pueden operar de manera uniforme en objetos de diferentes tipos, lo que resulta en un código más genérico, reutilizable y abstracto.
-
Mantenimiento del Código: Al reducir la duplicación y mejorar la legibilidad, el polimorfismo simplifica el mantenimiento de la base de código. Los cambios en el comportamiento pueden centralizarse o delegarse a las clases específicas sin afectar a otras partes del sistema.
Diferencia entre Polimorfismo y Herencia
Aunque están estrechamente relacionados, el polimorfismo y la herencia son conceptos distintos:
La Herencia es un mecanismo que establece una relación "ES-UN" entre clases (por ejemplo, "un Perro ES UN Animal"). Se centra en la reutilización de código y la creación de jerarquías de especialización.
El Polimorfismo es un concepto que permite que los objetos de diferentes clases (que están relacionadas por herencia o por "duck typing") sean tratados como objetos de una superclase común. Permite que estos objetos exhiban diferentes comportamientos mientras comparten una interfaz común. Se establece una relación "COMO-UN" o "SE COMPORTA COMO UN" (por ejemplo, "un Perro se comporta COMO UN Animal al hacer un sonido, pero lo hace de su propia manera").
Implicaciones del Polimorfismo
El polimorfismo es un pilar esencial para la abstracción y el encapsulamiento en la POO. Al permitir que objetos de diferentes tipos sean tratados a través de una interfaz común (la de la superclase o simplemente una interfaz de comportamiento), el polimorfismo oculta la complejidad de las implementaciones específicas de las subclases. Esto significa que los desarrolladores pueden escribir código que opera a un nivel de abstracción más alto, sin preocuparse por los detalles internos de cada tipo de objeto. Por ejemplo, un sistema de notificaciones puede tener un método enviar(mensaje) para cualquier Notificacion (Email, SMS, Push), y el polimorfismo asegura que la implementación correcta se use dinámicamente. Esto mejora la modularidad, la mantenibilidad y la capacidad de evolución del sistema.
En Python, la flexibilidad del "duck typing" amplifica el poder del polimorfismo. No es necesario que las clases compartan una jerarquía de herencia explícita para ser polimórficas; solo necesitan implementar los mismos métodos. Esto reduce la necesidad de jerarquías de herencia profundas y rígidas, promoviendo un diseño más plano y adaptable. Para un arquitecto de software, esto implica que la elección de la herencia para el polimorfismo debe ser cuidadosamente considerada; a menudo, una combinación de herencia (para compartir código base) e interfaces (o clases abstractas puras, usando el módulo abc en Python) es el enfoque más robusto y adaptable. Esto sugiere que, si bien la herencia define una relación "es-un" de implementación, las interfaces definen una relación "puede hacer" o "se comporta como" que es más flexible.
Ejemplos de Código (Python) Ejemplo de Polimorfismo con Animal y sus subclases:
# Superclase
class Animal:
def hacer_sonido(self):
print("El animal hace un sonido genérico.")
# Subclase Perro
class Perro(Animal):
def hacer_sonido(self):
print("El perro ladra: ¡Guau! ¡Guau!")
# Subclase Gato
class Gato(Animal):
def hacer_sonido(self):
print("El gato maúlla: ¡Miau! ¡Miau!")
# Clase principal para demostrar el polimorfismo
if __name__ == "__main__":
# Se crean objetos de las subclases, pero se referencian como el tipo de la superclase
animal1 = Perro() # Polimorfismo: un objeto Perro tratado como Animal
animal2 = Gato() # Polimorfismo: un objeto Gato tratado como Animal
# Al llamar al método, se ejecuta la implementación específica de cada objeto en tiempo de ejecución
print("--- Demostración de Polimorfismo ---")
animal1.hacer_sonido() # Llama al método sobrescrito en Perro
animal2.hacer_sonido() # Llama al método sobrescrito en Gato
# Ejemplo con una lista de objetos polimórficos
print("\n--- Lista de Animales ---")
animales =
animales.append(Perro())
animales.append(Gato())
animales.append(Animal()) # También podemos añadir una instancia de la superclase
for a in animales:
a.hacer_sonido() # Cada objeto ejecuta su propia versión de hacer_sonido()
En este ejemplo, animal1
y animal2
son declarados como tipo Animal
, pero en tiempo de ejecución, cuando se invoca hacer_sonido()
, se ejecuta la implementación específica de Perro
o Gato
respectivamente. Esto demuestra cómo un mismo método puede tener diferentes comportamientos según el tipo real del objeto.
Ejemplo de Polimorfismo con "Duck Typing" (Python):
class Pato:
def sonido(self):
print("El pato hace Quack.")
class Perro:
def sonido(self):
print("El perro hace Guau.")
class Gato:
def sonido(self):
print("El gato hace Miau.")
def hacer_sonido_animal(animal):
# Esta función no necesita saber el tipo exacto del objeto,
# solo que tiene un método 'sonido()'.
animal.sonido()
if __name__ == "__main__":
pato = Pato()
perro = Perro()
gato = Gato()
print("--- Demostración de Duck Typing ---")
hacer_sonido_animal(pato)
hacer_sonido_animal(perro)
hacer_sonido_animal(gato)
Este ejemplo ilustra el "Duck Typing" en Python. Las clases Pato
, Perro
y Gato
no comparten una clase base común, pero todas implementan el método sonido(). La función hacer_sonido_animal puede operar con cualquiera de estos objetos de manera polimórfica porque todos "se comportan como" un animal que puede hacer un sonido.