Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Polimorfismo

10/25
Recursos

Aportes 209

Preguntas 44

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Herencia: copy paste
Polimorfismo: edit copy paste

Buena clase, me gustaría agregar lo siguiente:

  • Python permite la herencia multiple.

  • Si las clases tienen un método con el mismo nombre y número de parámetros, gana (por así decirlo) el método de la clase que está más a la izquierda en cuanto a su implementación.

Ejemplo:

class Terrestre:

    def desplazar(self):
        print('El animal anda')


class Acuatico:

    def desplazar(self):
        print('El animal nada')


class Cocodrilo(Terrestre, Acuatico):
    """Abstracción de cocodrilo. Herencia multiple.
    
    Como Terrestre se encuentra más a la izquierda,
    sería la definición de desplazar de esta clase la
    que prevalecería.
    """
    pass

Algo interesante:

ciclista = Ciclista('Eduardo')
isinstance(ciclista, Persona) 
>>> True

Hola, dejo unos apuntes sobre el tema desde una perspectiva general en caso de que alguien pueda interesarle:

Polimorfismo
En computación, polimorfismo describe el concepto de que objetos de diferentes tupos pueden ser accedidos a través de la misma interfaz. Dicho de otra forma, es la habilidad de procesar objetos de forma distinta dependiendo de su tipo de dato o clase. Esto es la habilidad redefinir métodos para clases derivadas.
Por ejemplo, dada la clase forma, el polimorfismo le permite al programador definir métodos para encontrar el área según la clase derivada, sea circulo, rectángulos, cuadrados, etc. Sin importar que forma sea el objeto, el área debería poder hallar el resultado correcto si se aplica el polimorfismo correctamente.

**Existen dos tipos de polimorfismo: Dinámico y estático. **
• En el dinámico la creación del objeto ocurre en el run-time. Se le conoce también como ‘late-binding’ o ‘method overriding’ en diferentes clases (sobre escritura de método)
• En el caso del estático ocurre en el compile-time. Se le conoce también como ‘early binding’ o method overloading en diferentes clases (sobrecarga de métodos)
Python sin embargo no soporta la sobrecarga de métodos por default, por lo que no es tan necesario tener en cuenta estos tipos de polimorfismo.
Aunque herencia y polimorfismo están altamente relacionados no son exactamente lo mismo.

**La mayor diferencia entre polimorfismo y herencia **es que el primeo busca cambiar el comportamiento de la super clase en la subclase, mientras que en la herencia solo se busca usar la estructura y comportamiento de la superclase en una subclase.

De esta forma me parece que es más evidente el polimorfismo:

class Persona:

    def __init__(self, nombre):
        self.nombre = nombre
        self._action = 'Ando caminando'

    def avanza(self):
        print(f'{self._action}')


class Ciclista(Persona):

    def __init__(self, nombre):
        super().__init__(nombre)
        self._action = 'Ando moviendome en mi bicicleta'

    def avanza(self):
        super().avanza()

def main():
    persona = Persona('David')
    persona.avanza()

    ciclista = Ciclista('Daniel')
    ciclista.avanza()


if __name__ == '__main__':
    main()

En realidad pienso que la clase no estuvo muy buena respecto a este tema, en python no se puede ver muy bien pero si usamos otros lenguajes el polimorfismo es algo más complejo, pues es cambiar en ejecución la forma del objeto, un ejemplo es en los videojuegos tu llevas un carro pero de la nada quieres cambiar a una moto, pues no se crea otra instancia del vehiculo si no se llama al polimorfismo para que cambie la forma del objeto es decir que ahora en vez de ser un carro va a ser una moto… les dejo un ejemplo aqui abajo.

class Coche():

	def dezpla(self):
		print("Voy en 4 ruedas")


class Moto():

	def dezpla(self):
		print("Voy en 2 ruedas")



class Camion():

	def dezpla(self):
		print("Voy en 6 ruedas")


def dezplazamiento(vechiculo):
	vechiculo.dezpla()





miVehiculo=Coche()

dezplazamiento(miVehiculo)

Como pueden ver cree una función el mismo nombre y entiendo que en ese caso es igual a como explica en el curso pero en este caso solo mando una instancia llamada “miVehiculo” la funcion llama a un vehiculo y dependiendo a cual sea pues tiene el metodo diferente, asi se ve como cambia de forma un objeto, simplemente si fuera un videojuego le dirias al usuario en un if que escoga el vehiculo y dependiendo a su elección pues se manda a llamar al metodo pero no es necesario hacer instancias de todos los objetos si no existen.

Jajajaj bueno un poco complicado de explicar pero pienso que falto un poco más en esta clase.

Al profe lo patrocina American Eagle, desde el curso pasado usa la misma marca de camisas 🤣

Recuerden que si no van a modificar el comportamiento de un metodo en una subclase no vayan a repetir la llamda, como lo hace el profe, en el metodo “init”

class Person:

  def __init__(self, name):
    self.name = name

  @staticmethod
  def move():
    print("Keep Walking")

class Ciclist(Person):

  @staticmethod
  def move():
    print("Keep Roading")

p = Person("Peter")
p.move()

c = Ciclist('Clencio')
c.move()

Como pueden ver, no tuve que llamar el metodo “init” en la subclase “Ciclist” debido a que lo heredo de la superclase “Person”

Aqui dejo mi aporte, se me ocurrio, hacer una herencia de otra herencia, ya que podemos ir obteniendo las caracteristicas de varias clases padres, ademas de que lo que se me hizo interesante de esto, es que al hacer una subclase de 2da generacion por decir algo, siempre te pide los argumentos del la clase primogenita.

class Electronico:

    def __init__(self, nombre = None, precio = None, marca = None):
        self._nombre = nombre
        self._precio = precio
        self._marca = marca

    @property
    def nombre(self):
        return self._nombre

    @nombre.setter
    def nombre(self, nombre):
        self._nombre = nombre

    @property
    def precio(self):
        return self._precio

    @precio.setter
    def precio(self, precio):
        self._precio = precio

    @property
    def marca(self):
        return self._marca

    @marca.setter
    def marca(self, marca):
        self._marca = marca


    def Encendido(self):
        print(f"El dispositivo {self.nombre} se activo correctamente")


class Computadora(Electronico):

    def __init__(self,nombre, precio, marca, procesador = None, nucleos = None, t_grafica = None, m_board = None):
        super().__init__(nombre,precio,marca)
        self.procesador = procesador
        self._nucleos = nucleos
        self.t_grafica = t_grafica
        self.m_board = m_board

    @property
    def nucleos(self):
        return  self._nucleos

    @nucleos.setter
    def nucleos(self, nucleos):
        self._nucleos = nucleos

    def Encendido(self):
        print(f"Encendio la PC {self.nombre} con exito")

    def Tareas(self, nombre, n_nucleos):
        print(f"Esta realizando la tarea {nombre} con {n_nucleos}  nucleos asignados\n")

class Laptop(Computadora):

    def __init__(self,nombre, precio, marca):
        super().__init__(nombre,precio,marca)
        pass


if __name__ == '__main__':
    r2d2 = Electronico('R2 - D2', 999.999, '¿?')
    compu = Computadora('The Power',1000,'Varios','Core i5 5000', 4, 'gtx 1060', 'Aorus B450')
    lap = Laptop('RGB',1500,'MSI')

    r2d2.Encendido()
    print(f'Con precio de {r2d2.precio} y pertenece a {r2d2.marca}\n')

    compu.Encendido()
    print(f'Con precio de {compu.precio} con especificaciones {compu.procesador}, {compu.nucleos},\n '
          f'con una TG {compu.t_grafica} y una mother {compu.m_board}')
    compu.Tareas('Jugar Fornite',2)

    print(f'''{lap.nombre}
{lap.precio}
{lap.marca}
{lap.procesador}
{lap.nucleos}
{lap.m_board}''')```

Polimorfismo: Una característica poderosa

Ahora sí, considero que queda mejor aplicado lo de las potencias de Voltaje modificando el cálculo de volts y milivolts directamente en el método de cada clase aplicando polimorfismo:

class Voltaje:

    def __init__(self, corriente, resistencia):
        self.corriente = corriente
        self.resistencia = resistencia

    def calcular_voltaje(self):
        return self.corriente * self.resistencia
        

class MiliVoltaje(Voltaje):

    def __init__(self, corriente, resistencia):
        super().__init__(corriente, resistencia)

    def calcular_voltaje(self):
        return (self.corriente * self.resistencia)*1000
        

if __name__ == "__main__":
    voltios = Voltaje(corriente=100, resistencia=120)
    print(f'V: {voltios.calcular_voltaje()}')

    milivoltios = MiliVoltaje(100, 120)
    print(f'mV: {milivoltios.calcular_voltaje()}')

Aquí dejo mi aporte de Polimorfistmo 😃

#   -----  Clase -----
c =  7
t = 21

class Instrumento:
    def __init__(self, cuerdas, trastes):
        self.cuerdas = cuerdas
        self.trastes = trastes
      
    def tocar(self):
        print(f'Estos son los instrumentos de cuerdas que se tocar')

class Guitarra_Electrica(Instrumento):
    def __init__(self, cuerdas, trastes):
        super().__init__(cuerdas,trastes)

    def tocar(self):
        if self.cuerdas <= 8 and self.cuerdas >= 6 and self.trastes <=24 and self.trastes >= 21:
            print(f'Puedo tocar la guitarra eléctrica con {self.cuerdas} cuerdas y {self.trastes} trastes ')
        else:
            print('Pues la guitarra eléctrica no puedo tocar')

class Bajo(Instrumento):
    def __init__(self, cuerdas, trastes):
        super().__init__(cuerdas, trastes)

    def tocar(self):
        if self.cuerdas <= 6 and self.cuerdas >= 4 and self.trastes <=24 and self.trastes >= 21:
            print(f'Puedo tocar el bajo con {self.cuerdas} cuerdas y {self.trastes} trastes ')
        else:
            print('No hay bajos de más de 6 cuerdas')

class Guitarra_Acustica(Instrumento):
    def __init__(self, cuerdas, trastes):
        super().__init__(cuerdas, trastes)

    def tocar(self):
        if self.cuerdas >= 6 and self.trastes >= 12:
            print(f'Puedo tocar la guitarra acústica porque con más de 6 cuerdas y más de 12 trastes')
        else:
            print('La guitarra acústia de mínimo tiene 6 cuerdas')

def main():
    instrumento = Instrumento(6 , 24)
    instrumento.tocar()
    guitarra_electrica = Guitarra_Electrica(c, t)
    guitarra_electrica.tocar()
    bajo = Bajo (c , t)
    bajo.tocar()
    guitarra_acustica = Guitarra_Acustica (c , t)
    guitarra_acustica.tocar()

if __name__ == '__main__':
    main()```

Mi aporte de polimorfismo el cual establece el desplazamiento de distintos vehiculos, cabe destacar que este programa la clase padre se muestra en forma de funcion


class Coche():
    def desplazamiento(self):
        print('Me muevo en 4 ruedas')

class Moto():
    def desplazamiento(self):
        print('Me muevo en 2 ruedas')

class Camion():
    def desplazamiento(self):
        print('Me muevo en 6 ruedas')

def desplazamientoVehiculo(vehiculo): #aqui esta el poliformismo
                                     #ya que este objeto cambia de forma
    vehiculo.desplazamiento()

if __name__ == "__main__":
    miVehiculo=Moto() 
    desplazamientoVehiculo(miVehiculo)# 

Fuente: Pildoras Informaticas

En esta primera parte, un código SIN polimorfismo, donde para acceder al saludo de cada empleada/o hay que llamar al método específico definido en cada clase

class Operadora_1():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenos días, soy ',self.name, 'la Operadora del Turno Mañana')

        
class Operadora_2():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenos tardes, soy ',self.name, 'la Operadora del Turno Tarde')

class Operadora_3():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenas noches, soy ',self.name, 'la Operadora del Turno Noche')
        

class Sereno():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenas noches, soy ',self.name, ' en este momento no hay una Operadora disponible')


# sin POLIMORFISMO

luisa = Operadora_1('Luisa')
luisa.saludo()

anabel = Operadora_2('Anabel')
anabel.saludo()

lucila = Operadora_3('Lucila')
lucila.saludo()

nelson = Sereno('Nelson')
nelson.saludo()

En esta segunda parte, con la creación de un método (saludo_multiple) que se ‘enlaza’ a los métodos de saludos varios, accedemos al Polimorfismo.
Y luego, solo resta llamar siempre a ese único método, pasándole el parámetro de nuestro objeto, de manera que el propio método sabrá el comportamiento de ese objeto, accediendo. ala clase correspondiente

Espero se entienda!

class Operadora_1():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenos días, soy ',self.name, 'la Operadora del Turno Mañana')

        
class Operadora_2():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenos tardes, soy ',self.name, 'la Operadora del Turno Tarde')

class Operadora_3():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenas noches, soy ',self.name, 'la Operadora del Turno Noche')
        

class Sereno():
    def __init__(self,name):
        self.name = name

    def saludo(self):
        print('Buenas noches, soy ',self.name, ' en este momento no hay una Operadora disponible')



#CREACION DE UN MÉTODO QUE NOS PERMITIRÁ EL POLIMORFISMO

def saludo_multiple(empleada):
    empleada.saludo()




luisa = Operadora_1('Luisa')
saludo_multiple(luisa)

anabel = Operadora_2('Anabel')
saludo_multiple(anabel)

lucila = Operadora_3('Lucila')
saludo_multiple(lucila)

nelson = Sereno('Nelson')
saludo_multiple(nelson)

Explicación sencilla de esta clase, Link

Estos son mis apuntes completos sobre programación orientada a objetos en Python con contenido adicional al del curso:

GitHub

Si esto es todo lo que vamos a ver de poo en python… estoy bastante decepcionado, ha explicado solo algunos conceptos, a veces bastante mal y no se le ha dedicado el tiempo necesario para ello.

class Persona:

    def __init__(self, nombre):
        self.nombre=nombre
        
    @property
    def getNombre(self):
            return self.nombre

    def avanza(self):        
        print('anda caminando')

class Ciclista(Persona):
    def __init__(self,nombre):
        super().__init__(nombre)
    
    def avanza(self):
        print('anda en bicicleta')
 
def  main():
    persona=Persona('JUAN')
    print(f'{persona.getNombre}:') 
    persona.avanza()
    
    Ciclista1=Ciclista('LUIS')
    print(f'{Ciclista1.getNombre}:') 
    Ciclista1.avanza()

    
if __name__ == "__main__":
    main()

que mal que explica este profesor por dios! dan ganas de abandonar el curso con un profesor así! Se ve claramente que sabe muchísimo de la materia pero para transmitir sus conocimientos no es bueno.

Para que no se confundan tanto, es lo mismo si nunca usan el nombre, lo único que se quería ver era que podías usar el mismo nombre de método en distintas instancias e implementarlas de fomra distinta.
class Persona:

def __init__(self):
    pass

def avanza(self):
    print('Ando caminando')

class Ciclista(Persona):

def __init__(self):
    super().__init__()

def avanza(self):
    print('Ando moviendome en mi bicicleta')

def main():
persona = Persona()
persona.avanza()

ciclista = Ciclista()
ciclista.avanza()

if name == ‘main’:
main()

Creo que por fin voy entendiendo OOP :3 sobre todo eso de polimorfismo que me había costado entender.

polimorfismo en código

Es super útil saber que podemos modificar los métodos de las clases padre en las hijas.

En el caso de herencia múltiple, si las superclases tienen métodos con el mismo nombre e invocamos ese método desde la hija para saber el método de qué clase se va a llamar hay una función nombreCLase.mro()

# herencia en diamante
'''
'''
  A
|   \
B   C
 \D/
'''
'''
class A:
  pass

class B(A):
  pass

class C(A):
  pass

class D(B,C):
  pass

print(D.mro()) 

# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

print(D.__mro__)
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

en si lo que hizo fue sobrecargar o sobreescribir un metodo de la superclase, en python no se aprecia bien el tema de polimorfismo a menos que usemos typings. Poliformismo es cuando el objeto de la superclase contiene varios objetos de sus subclases pero no puede ser al reves

class Persona:

    def __init__(self, nombre):
        self.nombre = nombre

    def avanzar(self):
        print(f'Soy {self.nombre}y ando caminando :)')

class Ciclista(Persona):

    def __init__(self, nombre):
        super().__init__(nombre)

    def avanzar(self):
        print(f'Soy {self.nombre} y ando moviendome en mi bicicleta')

def run():
    persona = Persona('Alan')
    persona.avanzar()

    ciclista = Ciclista('Daniela')
    ciclista.avanzar()


if __name__ == '__main__':
    run()

: )

El polimorfismo es uno de los pilares básicos en la programación orientada a objetos, por lo que para entenderlo es importante tener las bases de la POO y la herencia bien asentadas.

El término polimorfismo tiene origen en las palabras poly (muchos) y morfo (formas), y aplicado a la programación hace referencia a que los objetos pueden tomar diferentes formas. ¿Pero qué significa esto?

Pues bien, significa que objetos de diferentes clases pueden ser accedidos utilizando el mismo interfaz, mostrando un comportamiento distinto (tomando diferentes formas) según cómo sean accedidos.

En lenguajes de programación como Python, que tiene tipado dinámico, el polimorfismo va muy relacionado con el duck typing.

Sin embargo, para entender bien este concepto, es conveniente explicarlo desde el punto de vista de un lenguaje de programación con tipado estático como Java. Vamos a por ello.
Polimorfismo en Java

Vamos a comenzar definiendo una clase Animal.

/```
/ Código Java
class Animal{
public Animal() {}
}

Y dos clases Perro y Gato que heredan de la anterior.

// Código Java
class Perro extends Animal {
public Perro() {}
}

class Gato extends Animal {
public Gato() {}
}


El polimorfismo es precisamente lo que nos permite hacer lo siguiente:

// Código Java
Animal a = new Perro();

Recuerda que Java es un lenguaje con tipado estático, lo que significa que el tipo tiene que ser definido al crear la variable.

Sin embargo estamos asignando a una variable Animal un objeto de la clase Perro. ¿Cómo es esto posible?

Pues ahí lo tienes, el polimorfismo es lo que nos permite usar ambas clases de forma indistinta, ya que soportan el mismo “interfaz” (no confundir con el interface de Java).

El siguiente código es también correcto. Tenemos un array de Animal donde cada elemento toma la forma de Perro o de Gato.

// Código Java
Animal[] animales = new Animal[10];
animales[0] = new Perro();
animales[1] = new Gato();

Sin embargo, no es posible realizar lo siguiente, ya que OtraClase no comparte interfaz con Animal. Tendremos un error error: incompatible types.

// Código Java
class OtraClase {
public OtraClase() {}
}
Animal a = new OtraClase();
animales[0] = new OtraClase();


Polimorfismo en Python

El término polimorfismo visto desde el punto de vista de Python es complicado de explicar sin hablar del duck typing, por lo que te recomendamos la lectura.

Al ser un lenguaje con tipado dinámico y permitir duck typing, en Python no es necesario que los objetos compartan un interfaz, simplemente basta con que tengan los métodos que se quieren llamar.

Podemos recrear el ejemplo de Java de la siguiente manera. Supongamos que tenemos un clase Animal con un método hablar().

class Animal:
def hablar(self):
pass


Por otro lado tenemos otras dos clases, Perro, Gato que heredan de la anterior. Además, implementan el método hablar() de una forma distinta.

class Perro(Animal):
def hablar(self):
print(“Guau!”)

class Gato(Animal):
def hablar(self):
print(“Miau!”)

A continuación creamos un objeto de cada clase y llamamos al método hablar(). Podemos observar que cada animal se comporta de manera distinta al usar hablar().

for animal in Perro(), Gato():
animal.hablar()

Guau!

Miau!


En el caso anterior, la variable animal ha ido “tomando las formas” de Perro y Gato. Sin embargo, nótese que al tener tipado dinámico este ejemplo hubiera funcionado igual sin que existiera herencia entre Perro y Gato, pero esta explicación la dejamos para el capítulo de duck typing

dado:

class Perro(Animal):
	def __init__(self):
		# etc...
		pass

Cual es la diferencia entre:

super().__init__() 

y

super(Animal, self).__init__()

?

Hola, les dejo mi código para el manejo de figuras geométricas de la clase de herencias. Tiene de todo un poco (hasta esta clase). Espero les sirva como ejemlo y también sus comentarios y sugerencias. Gracias !!

class Figure:
    """Clase base para manejo de figuras geométricas
    """

    def __init__(self, parameters : list) -> None:
        self.parameters = parameters

    @property
    def parameters(self) -> list:
        return self.__parameters[::] #variable privada que almacena los parámetros de una figura

    @parameters.setter
    def parameters(self, parameters : list) -> None:
        try:
            assert isinstance(parameters, list), f'Los parametros de una figura se deben almacenar en una lista'
            for n in parameters:
                try:
                    assert isinstance(n, (int, float)), f'El valor \"{n}\" no es válido'
                    self.__parameters = parameters[::]
                except AssertionError as ae:
                    raise ValueError(str(ae))
        except AssertionError as ae:
            raise TypeError(ae)

    def get_parameter(self, position : int) -> float:
        """Método para extraer un parámetro desde la lista de parámetros de la clase Figura.

        Args:
            position (int): Posición dentro de la lista de parámetros del valor a extraer (0, len(parametros)).

        Raises:
            IndexError: Se eleva una excepción de error de índice si se intenta leer alguna posición mayor a la longitud de la lista de parámetros.

        Returns:
            float: valor del parámetro almacenado en la posición "position" de la lista.
        """
        try:
            assert position < len(self.parameters), f'No se puede acceder la posición \"{position}\" de los parámetros de la Figura'
            return float(self.parameters[position])
        except AssertionError as ae:
            raise IndexError(ae)

    def set_parameter(self, value : float, position : int) -> None:
        """Método para sobre escribir un parámetro de la lista de parámetros de la clase Figura.

        Args:
            value (float): Valor del parámetro que se sobre escribirá
            position (int): Posición dentro de la lista de parámetros del valor que se escribe (0, len(parametros)).

        Raises:
            ValueError: Se eleva una excepción de error de valor si "value" es diferente a un entero o a un flotante
            IndexError: e eleva una excepción de error de índice si se intenta escribir alguna posición mayor a la longitud de la lista de parámetros.
        """
        try:
            assert position < len(self.parameters), f'No se puede acceder la posición \"{position}\" de los parámetros de la Figura'
            try:
                isinstance(value, (int, float)), f'El caracter \"{value}\" no es entero, ni flotante'
                list = self.parameters
                list[position] = value
                self.parameters = list

            except AssertionError as ae:
                raise ValueError(ae)
        except AssertionError as ae:
            raise IndexError(ae)                    

    @property
    def area(self):
        return None

    @property
    def perimeter(self):
        return None


class Rect(Figure):

    def __init__(self, width : float, height : float) -> None:
        super().__init__([width, height]) #Inicializa a la clase padre (Figura)

    @property # __parameters de Figura [ancho, alto]
    def width(self) -> float:
        return super().get_parameter(0)
        
    @width.setter
    def width(self, width : float) -> None:
        super().set_parameter(width, 0)                
        
    @property
    def height(self) -> float:
        return super().get_parameter(1)
        
    @height.setter
    def height(self, height : float) -> None:
        super().set_parameter(height, 1)

    @property
    def area(self) -> float:
        return float(self.width*self.height)

    @property
    def perimeter(self) -> float:
        return float(2*self.width + 2*self.height)                        


class Square(Figure):

    def __init__(self, side : float) -> None:
        super().__init__([side,]) #Inicializa a la clase padre (Figura)

    @property # __parameters de Figura [lado]
    def side(self) -> float:
        return super().get_parameter(0)
        
    @side.setter
    def side(self, side : float) -> None:
        super().set_parameter(side, 0)                

    @property
    def area(self) -> float:
        return float(4*self.side)

    @property
    def perimeter(self) -> float:
        return self.area


class Triangle(Figure):

    def __init__(self, side_a : float, side_b : float, side_c : float) -> None:
        super().__init__([side_a, side_b, side_c]) #Inicializa a la clase padre (Figura)

    @property # __parameters de Figura [lado_a, lado_b, lado_c]
    def side_a(self) -> float:
        return super().get_parameter(0)

    @side_a.setter
    def side_a(self, side_a : float) -> None:
        super().set_parameter(side_a, 0)             

    @property
    def side_b(self) -> float:
        return super().get_parameter(1)

    @side_b.setter
    def side_b(self, side_b : float) -> None:
        super().set_parameter(side_b, 1)

    @property
    def side_c(self) -> float:
        return super().get_parameter(2)

    @side_c.setter
    def side_c(self, side_c : float) -> None:
        super().set_parameter(side_c, 2)                          

    @property
    def area(self) -> float:
        """Cálculo del área de un tríangulo, según fórmula de herón
        A = sqrt(s*(s-lado_a)*(s-lado_b)*(s-lado_c))
        s = perimetro/2

        Returns:
            float: Área del triángulo
        """
        s = self.perimeter/2 #semi perímetro
        return round((s*(s - self.side_a)*(s - self.side_b)*(s - self.side_c))**0.5, 2)

    @property
    def perimeter(self) -> float:
        return float(self.side_a + self.side_b + self.side_c)     

    @property
    def is_valid(self) -> bool:
        """Determina si el triángulo de lados "lado_a", "lado_b", "lado_c" es válido,
        según el teorema de la desigualdad de los triángulos.

        Returns:
            bool: True si el triángulo es válido. False si el triángulo es inválido.

        NOTA: Todos los lados del triángulo deben ser ingresados previamente a ejecutar esta verificación.            
        """
        if self.side_a + self.side_b <= self.side_c:
            return False
        elif self.side_a + self.side_c <= self.side_b:
            return False
        elif self.side_b + self.side_c <= self.side_a:
            return False
        else:
            return True                                         


class Circle(Figure):

    PI = 3.1415926535897932384626433832795028841971893993751058209749445923078164062862089986280348253421170680

    def __init__(self, radius : float) -> None:
        super().__init__([radius, ]) #Inicializa a la clase padre (Figura)

    @property # __parameters de Figura [radio, ]
    def radius(self) -> float:
        return super().get_parameter(0)
        
    @radius.setter
    def radius(self, radius : float) -> None:
        super().set_parameter(radius, 0)                

    @property
    def area(self) -> float:
        return round(self.PI*(self.radius**2.0), 2)

    @property
    def perimeter(self) -> float:
        return round(2*self.PI*self.radius, 2)        


if __name__ == "__main__":
    rect = Rect(10, 20)
    print(f'Rectángulo: ancho={rect.width}, alto={rect.height}, area={rect.area}, perímetro={rect.perimeter}')

    rect.width = 1
    rect.height = 2
    print(f'Rectángulo: ancho={rect.width}, alto={rect.height}, area={rect.area}, perímetro={rect.perimeter}')

    sqr = Square(2)
    print(f'Cuadrado: lado={sqr.side}, area={sqr.area}, perímetro={sqr.perimeter}')

    sqr.side = 4
    print(f'Cuadrado: lado={sqr.side}, area={sqr.area}, perímetro={sqr.perimeter}')

    tri = Triangle(5, 7, 4)
    if(tri.is_valid):
        print(f'Triángulo: lado_a={tri.side_a}, lado_b={tri.side_b}, lado_c={tri.side_c}, area={tri.area}, perímetro={tri.perimeter}')
    else:
        print(f'El tríangulo con lados lado_a={tri.side_a}, lado_b={tri.side_b}, lado_c={tri.side_c} no es válido')        

    tri.side_a = 2
    tri.side_b = 4
    tri.side_c = 6
    if(tri.is_valid):
        print(f'Triángulo: lado_a={tri.side_a}, lado_b={tri.side_b}, lado_c={tri.side_c}, area={tri.area}, perímetro={tri.perimeter}')
    else:
        print(f'El tríangulo con lados lado_a={tri.side_a}, lado_b={tri.side_b}, lado_c={tri.side_c} no es válido')        

    circ = Circle(2)
    print(f'Círculo: radio={circ.radius}, area={circ.area}, perímetro={circ.perimeter}')

    circ.radius = 4
    print(f'Círculo: radio={circ.radius}, area={circ.area}, perímetro={circ.perimeter}')

Ejemplo de Polimorfismo

class Mago():
    def __init__(self):
        pass
    def accion(self):
        print("Bola de fuego")

class Warrior():
    def __init__(self):
        pass
    def accion(self):
        print("Ataque de furia")

class Arquero():
    def __init__(self):
        pass
    def accion(self):
        print("Ataque con arco")

def accion_personaje(objeto):
    objeto.accion()

def run():
    personaje = Warrior()
    accion_personaje(personaje)

if __name__ == "__main__":
    run()```

Hola,

Agregue polimorfismo a mi código, creo que queda un poco más entendible 😃

class animal:

    def __init__(self, type):
        self.type = type

    def show_type(self):
        return self.type

    #Polimorfismo
    def walk(self):
        print('walking') 

class dog(animal):

    def __init__(self, type, name, breed, color, age):
        super().__init__(type)
        self.__name = name
        # "_"variable: Protegidos
        # "__"variable: Privado // Para llamarla "instancia.'_clase'__variable"
        self.__breed = breed
        self.color = color
        self.age = age

    def __str__(self):
        return f"Hi, My name is {self.__name},\nI am one of the Enzo's dogs ;)\nI like to: \n- sleep: {self.sleep()} {self.sleep()}\n- eat: {self.eat()}\n- and bark: {self.bark()} {self.bark()}\noh, don't worry I am {self.show_type()}\n"

    # Polimorfismo
    def walk(self):
        super().walk()
        print('and moving the tale')

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        print("Changing name...")
        self.__name = new_name
        print(f"The new name is... {self.name}")

    @name.deleter
    def name(self):
        print("Deleting name")
        del self.__name

    def look_name(self):
        return self.__name

    def sleep(self):
        return 'Zzz'
    
    def eat(self):
        return 'Chewing...'
        #Es necesario usar 'return' para que se muestre en el string, si usas 'print' lo que haces es invocar una función
    
    def bark(self):
        return '¡woof!'


if __name__ == '__main__':
    dog_1 = dog('domestic','Janis', 'Labrador Retriever', 'off-white', 7)
    dog_2 = dog('domestic','Rodolfo', 'Labrador Retriever', 'brown or chaufa', 1)
    # print(str(dog_1))
    # print(str(dog_2))
    dog_1.walk()

Devuelve

walking
and moving the tale

Los métodos especiales de las clases también se pueden redefinir. Como es el caso del método str() y len().

Cree la clase película y redefiní estos métodos

class Pelicula:
    # Constructor de clase
    def __init__(self, titulo, duracion, lanzamiento):
        self.titulo = titulo
        self.duracion = duracion
        self.lanzamiento = lanzamiento
        print("Se ha creado la película", self.titulo)

    # Redefinimos el método string
    def __str__(self):
        return f'{self.titulo} lanzada en {self.lanzamiento} con una duración de {self.duracion} minutos'

    # Redefinimos el método length
    def __len__(self):
        return self.duracion


#Instancia
p = Pelicula("El Padrino", 175, 1972)
print(str(p))
print(len(p))
print(p)

Salida

El Padrino lanzada en 1972 con una duración de 175 minutos
175
El Padrino lanzada en 1972 con una duración de 175 minutos

Buenas noches gente lindaque está tomando este curso de POO, les comparto la pieza de código que realicé para esta clase:

class Persona:
    
    def __init__(self, nombre):
        self.nombre = nombre
    
    def avanza(self):
        print('Ando caminando')

class Ciclista(Persona): #Concepto de Herencia, esto se lee: La clase ciclist extiende a la superclase Persona
    
    def __init__(self, nombre):
        super().__init__(nombre)
    
    def avanza(self):
        print('Ando moviendome en mi bicicleta') #Esto "especializa" la herencia de la superclase, esta parte del código
                                                 #es la parte principal de este ejemplo de polimorfismo.
def run():
    
    persona = Persona('David')
    persona.avanza()
    
    cilcista = Ciclista('Daniel')
    cilcista.avanza()

if __name__ == '__main__':
    run()

No sé si estoy mal, pero esto en realidad lo qué es, es un sobreescritura de métodos, y es una parte del polimorfismo, pero el polimorfismo en sí, es utilizado de una forma diferente en cuanto a la utilizacion de instancias y lo demas.

spoiler 😃

  • El Polimorfismo es la base que nos permite crear verdaderas clases abstractas e interfaces

este articulo nos da un resumen:
Implementing an Interface in Python

Una de las caracteristicas de polimorfismo en .NET es q me permite tener el mismo nombre de la funcion siempre que la cantidad de parametros sea diferente, en Python aplica este comportamiento de la misma manera?

Con esto de polimorfismo pude recordar que en el curso de javascript( fundamentos) había algo similar con la herencia prototypal, pues con esto lo que se hacia es pasarle los prototipos(cada funcion tiene prototipos y en Javascript existen prototipos , no clases) del prototipopadre al prototipohijo.Sin embargo, cuando se crea una metodo para el prototipohijo con el mismo nombre de un metodo en el prototipo padre, pues la del hijo “pisa” al del padre, llamandose asi a solo una.

Pienso que esto por dentro debe ser similar 😄! Que opinan?

Se me ocurre que para modelar créditos y/o seguros debe ser util, ya ue un crédito puede ser definido como la super clase y las variantes de comportamieto cambien. más alla de la temporalidad de pago, plazo monto y tasa anual. …

Mi concepto nemotécnico del polimorfismo es: Los métodos de las superclases son camaleones.

Una forma muy importante de utilizar el polimorfismo es a través de las generalizaciones. Si necesitas crear un método que sea capaz de realizar una acción sobre toda una categoría de objetos, envías tu objeto específico como parámetro pero lo tratas como el objeto general.

lo use con anterioridad en C#

Excelente ejercicio, fácil de entender.

Si de hecho lo utilice en facturacion electronica ya que tanto las facturas como las notas credito generan un xml donde su estructura es distinta, entonces cada vez que se generaba una factura entonces utilizaba la estructura correspondiente al tipo de comprobante de igual manera para la nota credito.

No me quedo muy claro el ejemplo, para que sirve no entendi

Este ejemplo les puede ayudar !

Creo que una aplicación que puede tener el polimorfismo sería tener personas con permisos de administrador en un sistema, esto usando la misma estructura de registro que con cualquier usuario normal.

El método super() es muy poderoso, en este ejemplo podemos poner una persona que su método avanza imprimie “estoy avanzando” pero que el resto del método está especidifcado en las clases que hereda.


class Persona:
    def __init__(self, nombre) -> None:
        self.nombre = nombre

    def avanza(self):
        print("Estoy avanazando!")


class Peaton(Persona):
    def __init__(self, nombre) -> None:
        super().__init__(nombre)

    def avanza(self):
        super().avanza()
        print("Uso mis pies para avanzar")


class Ciclista(Persona):
    def __init__(self, nombre) -> None:
        super().__init__(nombre)

    def avanza(self):
        super().avanza()
        print("Ando moviendome en bicicleta")


if __name__ == "__main__":
    bren = Peaton("Brendita")
    karlos = Ciclista("Karlos")

    bren.avanza()
    karlos.avanza()

Y esto devuelve en la terminal

Estoy avanazando!
Uso mis pies para avanzar
Estoy avanazando!
Ando moviendome en bicicleta

Es un poco parecido a los decoadores al final estamos agregando funcionalidad una de las funciones (métodos)

Aquí mi ejemplo que hice para comprende mejor el tema.

class transport:
    def __init__(self, brand, name):
        self.brand = brand
        self.__name = name 
    
    def moves(self):
        pass

    @property
    def name(self):
        return self.__name

class plane(transport):
    def __init__(self, brand, name):
        super().__init__(brand, name)
    def avanza(self):
        print('I fly')

class sportcar(transport):
    
    def __init__(self, brand, name):
        super().__init__(brand, name)
    
    def avanza(self):
        print('I move on the rode')

def main():
    miplane = plane('Boeing','ZL-2000')
    miplane.avanza()
    print(miplane.name)
    

    micar = sportcar('Chev','aveo')
    micar.avanza()

if __name__ == '__main__':
    main()

Bueno, segun lo que investigue para aterrizar en el tema.

Herencia afecta a las clases, si vas a crear una nueva clase que tiene similitud a alguna anterior, simplemente puedes convertir la clase existente en padre y a la nueva en sub-clase. Adoptando asi caracteristicas de la clase padre.

Y en los detalles de la nueva clase entra el polimorfismo pues este afecta a los metodos:

Esto es porque si tienes que re-estructurar un metodo ya existente en la clase padre desde la sub-clase lo puedes hacer y este cambio solo estaria en la sub-clase y a esto se le dice polimorfismo.

Espero les sirva, si tienen alguna duda o discrepancia por favor comenten

En programación orientada a objetos se denomina polimorfismo a la capacidad que tienen los objetos de una clase de responder al mismo mensaje o evento en función de los parámetros utilizados durante su invocación.

Definición: polimorfismo (en POO) es la capacidad que tienen ciertos lenguajes para hacer que, al enviar el mismo mensaje (o, en otras palabras, invocar al mismo método) desde distintos objetos, cada uno de esos objetos pueda responder a ese mensaje (o a esa invocación) de forma distinta.

Genial, tenia esta duda realizando mi reto de la clase pasada:
https://platzi.com/comentario/3018340/
donde construi la clase padre de SerVivo con metodos de reproduccion y muerte, y otras clases hijas como Perro y Pollo, pero los metodos de reproduccion eran diferentes (uno de mamifero y otro oviparo). Opte por hacer el ejercicio mas sencillo donde simplemente print(“tenian hijitos”) jajaja pero fue suficiente para aprender el concepto de herencia.

Hola buenos dias, por qué no se pueden ver los comentarios de aportes?

Un ejemplo muy interesante y más complejo es el polimorfismo de los operadores en C++. Por ejemplo, podemos decidir el comportamiento que va a tener el operador de suma ‘+’ para diferentes tipos de datos. Imagina que tenemos dos instancias de la clase Coordenada, en C++ podemos definir el operador ‘+’ para realizar la suma de coordenadas, claro que realizar eso es un concepto avanzado del lenguaje, el uso sería de la siguiente forma:

Coordenada coordenada1(1, 1);
Coordenada coordenada2(2, 2);
Coordenada coordenada3 = coordenada1 + coordenada2; //Aquí esta la magia del polimorfismo de C++

me demore mucho intentando entender bien esto pero creo que este ejemplo que hice le puede ayudar a alguno a entender

class Vehiculo: # esta es la clase vehiculo
    
    def __init__ (self, velocidad , modelo):
        self.velocidad = velocidad
        self.modelo = modelo

    def medio(self): 
        x = input('indique el medio : ')
        print(f'El  {self.modelo} se mueve por {x} medio a: {self.velocidad}')

class Carro(Vehiculo):

    def __init__(self, velocidad, modelo):
        super().__init__(velocidad,modelo)

    def medio(self):
        
        print(f'el {self.modelo} se mueve por tierra a: {self.velocidad}')


class Avion(Vehiculo):

    def __init__(self, velocidad, modelo):
        super().__init__(velocidad, modelo)
    
    def medio(self):
        print(f'el {self.modelo} se mueve por aire a: {self.velocidad}')


def run():
    carro1 = Carro('20km/h', 'mazada')
    carro1.medio()

    avion1= Avion('140km/h', 'cesna')
    avion1.medio()

    nave = Vehiculo('9999km/h','XX')
    nave.medio()



if __name__ == '__main__':
    run()
    
class Persona():
	def __init__(self, nombre):
		self.nombre = nombre

	def avanza(self):
		print('Avanza en dos patas.')

class Ciclista(Persona):

	def avanza(self):
		print('Avanza en dos ruedas')

ciclista1 = Ciclista('Jose')
print(ciclista1.nombre)  ###Imprime: Jose

En el ejemplo que dio el profe no es necesario usar super() .
Sólo se usa super() cuando tengo un método en mi subclase(clase hija) con el mismo nombre de aquel de mi super-clase y quiero agregarle otras funcionalidades/atributos ADEMÁS de los ya incluido en la super-clase.
Esto no pasa con init ya que en nuestra subclase no le estamos agregando nada. Distinto fuera si quisiéramos incluir un init en Ciclista que nos diese la edad del ciclista (ahí si usaríamos super()).

Polimorfismo: Comportamientos distintos pueden estar asociados al mismo nombre.

“aidi-í” = IDE = Integrated Development Environment

Por si alguien necesitaba esa aclaración.

aqui esta mejor explicado la parte de herencia en el codigo jeje

al fin una clase q entendiii wi jajajaja

se me ocurio este ejemplo

class Pokemon:

    def __init__(self,nombre):
        self.nombre = nombre

    def hablar(self, mensaje):
        return mensaje

class Pikachu(Pokemon):

    def __init__(self,nombre):
        super().__init__(nombre)

    def hablar(self, mensaje):
        self.mensaje = 'pika pika'
        return mensaje


class Squero(Pokemon):

    def __init__(self,nombre):
        super().__init__(nombre)

    def hablar(self, mensaje):
        self.mensaje = 'squero, squero'
        return mensaje

class Furret(Pokemon):

    def __init__(self,nombre):
        super().__init__(nombre)

    def hablar(self, mensaje):
        self.mensaje = """
        Unos Pokémon vuelan al cielo
Pero yo puedo caminar (ca-mi-nar)
Y otros pueden cavar profundo
Pero yo puedo caminar (ca-mi-nar)
No sé exactamente a donde voy a ir
Yo caminaré y estaré justo ahí
No me hace falta tener una razón
Contigo yo estoy

Algunos pueden gritar, lanzar lásers
Pero puedo caminar (ca-mi-nar)
        """
        return mensaje

def main():
    pikachu =Pikachu('pikachu')
    pikachu.mensaje()

    squero =Squero('pikachu')
    squero.mensaje()

    furret = Furret('Furret')
    furret.mensaje()


if __name__ == '__main__':
    main()

init (self, bob el constructor)

👍👍👍

  • La habilidad de tomar varias formas.
  • En Python, podemos cambiar el comportamiento de una superclase para adaptarlo a la subclase.

Tomando en cuenta la actividad de la clase de herencia frente a las figuras, no todos los elementos van a tener la misma forma de sacar el área por lo que se debería aplicar el polimorfismo en esos casos.

Adicionando al código el nombre de la persona que llama:


class Persona:

    def __init__(self, nombre):
        self.nombre = nombre

    def avanza(self):
        print(f'Soy {self.nombre} una persona, ando caminando.')


class Ciclista(Persona):

    def __init__(self, nombre):
        super().__init__(nombre)

    def avanza(self):
        print(f'Soy {self.nombre} un ciclista, ando moviéndome en mi bicicleta.')

def main():
    persona = Persona('David')
    persona.avanza()

    ciclista = Ciclista('Daniel')
    ciclista.avanza()


if __name__ == '__main__':
    main()

Imagínense crear una superclase Homo Sapiens, y crear una subclase para cada personas del mundo. Ahora que lo pienso, seria como un ID digital.

<code> 
class Desplazamiento:
    def movimiento(ser_vivo):
        print(ser_vivo.nombre+' se esta moviendo')
        
class Persona(Desplazamiento):
    def __init__(self, nombre):
        self.nombre = nombre 

class Animal(Desplazamiento):
    def __init__(self, nombre):
        self.nombre = nombre 
        
persona = Persona('pedro')
animal = Animal('firulais')

ser_vivo = Desplazamiento
ser_vivo.movimiento(persona)
ser_vivo.movimiento(animal)

Tanto una persona como un animal se desplazan
el metodo movimiento aplica a una persona como a un animal

Para copiar los métodos en Python, es tan sencillo, como poner exactamente el mismo nombre, con los mismos parámetros.

En Python, solo tenemos que tomar el nombre del método de nuestra super clase, para que podamos modificarlo.

El Poliformismo, es clave para darnos la posibilidad de tomar características de nuestra clase superior, y modificarlas de la forma adecuada.

La técnica de polimorfismo de la POO significa la capacidad de tomar más de una forma. Una operación puede presentar diferentes comportamientos en diferentes instancias. El comportamiento depende de los tipos de datos utilizados en la operación. El polimorfismo es ampliamente utilizado en la aplicación de la herencia.

Lo que entendí y veo de referencia es que en la herencia se re utiliza código haciendo el uso de la función super() y que al momento de invocar la subclase, esta tendrá el acceso al método de la superclase. Mientras que en polimorfismo, también se tiene accesos a los métodos de la superclase, podemos crear el método en la subclase para generar nuevas formas 😃

a alguien mas le da ansiedad que el profe no tenga un alias para python3.7

Alguien alguna vez ha pensado que seria super chevere que las litas de python tuvieran un metodo swap?

Que bueno que en python todo es una clase 😊.

class SwapableList(list):
    """Extends list class to swap to elements given
    its indexes if they exist."""

    def swap(self, index_1, index_2):
        """Swaps two elements from a list if their
        indexes exist.

        index_1 = int index of first element to swap
        index_2 = int index of second element to swap
        """
        try:
            temp = self[index_1]
            self[index_1] = self[index_2]
            self[index_2] = temp
        except IndexError:
            raise IndexError


swapable_list = SwapableList((1, 2, 3, 4, 5))
swapable_list.swap(0, -1)

print(swapable_list)

Hasta que te cambias de ropa xD todo el curso pasado & la mitad de este fue con la misma.

El polimorfismo es

🐶 🐱 Mi aporte

De los mejores ejemplos para entender 🐶 🐱

class Animals:

    def __init__(self, name, message):
        
        self.name = name
        self.message = message
    
    def says(self):
        print(f'{self.name} says {self.message}')

class Dog(Animals):
    def __init__(self, name, message):
        super().__init__(name, message)
       
class Cat(Animals):    
    def __init__(self, name, message):
        super().__init__(name, message)


def main():
    dog = Dog('Dog','WOW!')
    dog.says()

    cat = Cat('Cat', 'MEOW')
    cat.says()

if __name__ == '__main__':
    main()

Muy interesante aprender estos conceptos. Quedaron muy claros

Luego de repasar todo el curso y practicar con ejercicios lo estoy entendiendo todo mucho mejor. Inicialmente estaba muy perdido. Hay que practicar conceptos básicos de cursos anteriores y volver. Funciona.

😃

Con esta clase podemos responder lo siguiente:

  • ¿En qué consiste el polimorfismo?
  • ¿Para qué podríamos utilizarlo?

📙 Polimorfismo
Es la capacidad que tiene un objeto de presentar diferentes comportamientos al momento de realizar una acción, el polimorfismo se presenta cuando se aplica el principio de Herencia.

Tengo una pregunta:
Nos podemos dar cuanta del polimorfismo cuando tenemos métodos con el mismo nombre en diferentes clases que estén relacionadas ?

Mi humilde aporte para sentir que si estoy usando una función heredada modificada. Solo uso la variable de nombre que no asigné directamente en la clase Ciclista pero que si se asigna en la super clase Persona,

class Persona:
    def __init__(self, nombre):
        self.nombre = nombre

    def avanza(self):
        print('Yo ' + self.nombre + ' camino en mi cuarto u_u')

class Ciclista(Persona):
    def __init__(self, otronombre):
        super().__init__(otronombre)

    def avanza(self):
        print('Yo ' + self.nombre + ' quisiera poder salir en baica :c')

def main():
    
    persona = Persona('Erick')
    ciclista = Ciclista('Eduardo')

    persona.avanza()
    ciclista.avanza()

if __name__ == '__main__':
    main()


Se cortóel cabello :000

Le agregue que puedes indicar el nombre de la persona que camina y el del ciclista

class Persona:

    def __init__(self, nombre):
        self.nombre = nombre

    def avanza(self):
        print(f"{self.nombre} esta caminando")
    

class Ciclista(Persona): 

    def __init__(self, nombre):
        super().__init__(nombre)

    def avanza(self):
        print(f"{self.nombre} va en su bicicleta")


def main():
    persona = Persona(input("Ingresa un nombre del caminador: "))
    persona.avanza()

    ciclista = Ciclista(input("Ingresa un nombre del ciclista: "))
    ciclista.avanza()


if __name__ == "__main__": 
    main()

Un ejemplo de herencia y polimorfismo


class FiguraGeometrica:

    def __init__(self,base,altura):
        self.base = base
        self.altura = altura

    def obtenerArea(self):
        return self.base * self.altura

    def obtenerPerimetro(self):
        return self.base*4

class Cuadrado(FiguraGeometrica):

    def __init__(self,lado):
        super().__init__(lado,lado)

class Rectangulo(FiguraGeometrica):

    def __init__(self,base,altura):
        super().__init__(base,altura)
    
    def obtenerPerimetro(self):
        return (self.base*2) + (self.altura*2)

class Triangulo(FiguraGeometrica):

    def __init__(self,base,altura):
        super().__init__(base,altura)

    def obtenerArea(self):
        return (self.base * self.altura)/2

    def obtenerPerimetro(self):
        return self.base*3

def main():
    cuadrado = Cuadrado(2)
    print(f'Area del cuadrado {cuadrado.obtenerArea()}')
    print(f'Perimetro del cuadrado {cuadrado.obtenerPerimetro()}')

    rectangulo = Rectangulo(2,4)
    print(f'Area del rectangulo {rectangulo.obtenerArea()}')
    print(f'Perimetro del rectangulo {rectangulo.obtenerPerimetro()}')

    trianguloEquilatero = Triangulo(3,5)
    print(f'Area triangulo {trianguloEquilatero.obtenerArea()}')
    print(f'Perimetro triangulo {trianguloEquilatero.obtenerPerimetro()}')


if __name__ == "__main__":
    main()

Hola, comparto con ustedes el ejercicio que me inventé para practicar el tema y combinarlo con el anterior de Herencia.
.
La SUPERCLASE Empleados contiene las funciones de Nombre Completo, Email y Salario2021. Las SUBCLASES DataScientist y Manager usan estas mismas funciones pero de forma distinta.
.
Reciben parámetros adicionales como Ranking y Área, para que las funciones Email y Salario2021 operen diferente.
.
Esto muestra la Terminal:

.
El código lo pueden ver acá en mi GitHub:
https://github.com/SDCASTAPEREZ/poo_y_algoritmos/blob/master/Herencia-Poliformismo_Ejercicio.py
.
Espero les sea de utilidad para nunca parar de aprender 😄

una forma de ver al polimorfi¿smo, es con la selección natural y los pinzones. Superclase = pájaró, Herencia = pinzones, Polimorfismo = todas las subespecies de pinzones deontro de la isla Galapagos.

Mi pequeño aporte:

# Coding UTF-8

class Computadora:

    def __init__(self, tipo, marca, color):
        self.tipo = tipo
        self.marca = marca 
        self.color = color

    def forma(self):
        print(f'Marca: {self.tipo}, {self.marca}, {self.color}')

class computadoraForma(Computadora):

    def __init__(self, tipo, marca, color):
        super().__init__(tipo, marca, color)

    def forma(self):
        print(f'Marca: {self.tipo}, {self.marca}, {self.color}')


def main():
        computadora = Computadora('Escritorio', 'DELL', 'Negra')
        computadora.forma()

        computadoraforma = computadoraForma('Laptop', 'HP', 'Azul')
        computadoraforma.forma()

if __name__ == "__main__":
    main()

Entonces solo es es un método con el mismo nombre del método de la super clase, pero modificado de acuerdo a la nueva sub clase.

Es muy bueno esto del polimorfismo ya que si tengo 100 personas me y una sola por ejemplo es la que anda en auto y el resto camina las 99 que caminan se generan solas y el que va en auto lo genera uno de esta manera es super escalable.

Daría lo mismo poner un método con otro nombre que haga exactamente lo mismo?

El polimorfismo es basicamente la modificacion de metodos dentro de clases en las que se pueda heredar, muy util para cuando se necesite tener una referencia mas clara, abajo les comparto mi resultado con el mundo de Pokemon jaja

Me recordó mucho a los rpgs de texto que jugaba Sheldon en TBBT ;D

Con la clase de herencia entendí anticipandamente el polimorfismo. Adecuaando nuestros objetos a cualquier forma