Visión general
- Aprenda sobre la herencia en la programación orientada a objetos y varias formas de herencia
- Comprender la anulación de métodos y la función super () en el mundo de la programación orientada a objetos
Introducción
La herencia es uno de los aspectos más importantes de la programación orientada a objetos (OOP). La clave para comprender la herencia es que proporciona reutilización del código. En lugar de escribir el mismo código, una y otra vez, podemos simplemente heredar las propiedades de una clase en la otra.
Esto, como puede imaginar, ahorra mucho tiempo. ¡Y el tiempo es dinero en ciencia de datos!
La programación orientada a objetos se trata de objetos del mundo real y la herencia es una forma de representar las relaciones del mundo real. He aquí un ejemplo: coche, autobús, bicicleta – todos ellos pertenecen a una categoría más amplia denominada Vehículo. Eso significa que han heredado las propiedades de los vehículos de clase, es decir, todos se utilizan para el transporte.
Podemos representar esta relación en código con la ayuda de la herencia.
Otra cosa intrigante sobre la herencia es que es de naturaleza transitiva. Pero ¿qué significa esto? Veremos en detalle más adelante en este artículo. Python también admite varios tipos de herencia que cubriré en detalle en este artículo.
Este es el segundo artículo de la serie de artículos relacionados con la programación orientada a objetos. Lea también el primer artículo:
Tabla de contenido
- ¿Qué es la herencia en la programación orientada a objetos?
- Diferentes formas de herencia en la programación orientada a objetos
- Herencia única
- Herencia múltiple
- Herencia multinivel
- Herencia jerárquica
- Herencia híbrida
- Anulación de método
- La función super ()
¿Qué es la herencia en la programación orientada a objetos?
La herencia es el procedimiento en el que una clase hereda los atributos y métodos de otra clase. La clase cuyas propiedades y métodos se heredan se conoce como clase principal. Y la clase que hereda las propiedades de la clase principal es la clase Child.
Lo interesante es que, junto con las propiedades y métodos heredados, una clase hija puede tener sus propias propiedades y métodos.
Puede usar la siguiente sintaxis: para implementar la herencia en Python:
class parent_class: body of parent class class child_class( parent_class): body of child class
Veamos la implementación:
class Car: #parent class def __init__(self, name, mileage): self.name = name self.mileage = mileage def description(self): return f"The {self.name} car gives the mileage of {self.mileage}km/l" class BMW(Car): #child class pass class Audi(Car): #child class def audi_desc(self): return "This is the description method of class Audi."
obj1 = BMW("BMW 7-series",39.53) print(obj1.description()) obj2 = Audi("Audi A8 L",14) print(obj2.description()) print(obj2.audi_desc())
Producción:
Hemos creado dos clases secundarias, a saber, «BMW» y «Audi», que han heredado los métodos y propiedades de la clase principal «Coche». No hemos proporcionado funciones y métodos adicionales en la clase BMW. Considerando que hay un método adicional dentro de la clase Audi.
Observe cómo los objetos de las clases secundarias pueden acceder al método de instancia description () de la clase principal con la ayuda de obj1.description () y obj2.description (). Y también se puede acceder al método separado de la clase Audi mediante obj2.audi_desc ().
Podemos verificar la clase base o padre de cualquier clase usando un atributo de clase incorporado __bases__
print(BMW.__bases__, Audi.__bases__)
Como podemos aquí, la clase base de ambas subclases es Coche. Ahora, veamos qué sucede cuando se usa __base__ con la clase padre Car:
print( Car.__bases__ )
Siempre que creamos una nueva clase en Python 3.x, se hereda de una clase básica incorporada llamada Objeto. En otras palabras, la clase Object es la raíz de todas las clases.
Formas de herencia en la programación orientada a objetos
En general, hay cinco formas de herencia basadas en la participación de las clases de padres e hijos.
1. Herencia única
Esta es una forma de herencia en la que una clase hereda solo una clase principal. Esta es la forma simple de herencia y, por lo tanto, también se conoce como herencia simple.
class Parent: def f1(self): print("Function of parent class.") class Child(Parent): def f2(self): print("Function of child class.") object1 = Child() object1.f1() object1.f2()
Aquí, la clase Child hereda solo una clase Parent, por lo tanto, este es un ejemplo de herencia simple.
2. Herencia múltiple
Una herencia se convierte en herencias múltiples cuando una clase hereda más de una clase principal. La clase secundaria después de heredar propiedades de varias clases principales tiene acceso a todos sus objetos.
class Parent_1: def f1(self): print("Function of parent_1 class.") class Parent_2: def f2(self): print("Function of parent_2 class.") class Parent_3: def f3(self): print("function of parent_3 class.") class Child(Parent_1, Parent_2, Parent_3): def f4(self): print("Function of child class.") object_1 = Child() object_1.f1() object_1.f2() object_1.f3() object_1.f4()
Aquí tenemos una clase Child que hereda las propiedades de las clases de tres padres Parent_1, Parent_2 y Parent_3. Todas las clases tienen funciones diferentes y todas las funciones se llaman usando el objeto de la clase Child.
Pero supongamos que una clase hija hereda dos clases que tienen la misma función:
class Parent_1: def f1(self): print("Function of parent_1 class.") class Parent_2: def f1(self): print("Function of parent_2 class.") class Child(Parent_1, Parent_2): def f2(self): print("Function of child class.")
Aquí, las clases Parent_1 y Parent_2 tienen la misma función f1 (). Ahora, cuando el objeto de la clase Child llama a f1 (), dado que la clase Child hereda las dos clases padre, ¿qué crees que debería suceder?
obj = Child() obj.f1()
Pero, ¿por qué no se heredó la función f1 () de la clase Parent_2?
En herencia múltiple, la clase secundaria busca primero el método en su propia clase. Si no se encuentra, busca en las clases padre profundidad_primero y orden de izquierda a derecha. Dado que este fue un ejemplo fácil con solo dos clases principales, podemos ver claramente que la clase Parent_1 se heredó primero, por lo que la clase secundaria buscará el método en la clase Parent_1 antes de buscar en la clase Parent_2.
Pero para problemas de herencia complicados, es difícil identificar el pedido. Entonces, la forma real de hacer esto se llama Orden de resoluciónLa "resolución" se refiere a la capacidad de tomar decisiones firmes y cumplir con los objetivos establecidos. En contextos personales y profesionales, implica definir metas claras y desarrollar un plan de acción para alcanzarlas. La resolución es fundamental para el crecimiento personal y el éxito en diversas áreas de la vida, ya que permite superar obstáculos y mantener el enfoque en lo que realmente importa.... de método (MRO) en Python. Podemos encontrar el MRO de cualquier clase usando el atributo __mro__
Child.__mro__
Esto indica que la clase Child visitó primero la clase Parent_1 y luego Parent_2, por lo que se llamará al método f1 () de Parent_1.
Tomemos un ejemplo un poco complicado en Python:
class Parent_1: pass class Parent_2: pass class Parent_3: pass class Child_1(Parent_1,Parent_2): pass class Child_2(Parent_2,Parent_3): pass class Child_3(Child_1,Child_2,Parent_3): pass
Aquí, la clase Child_1 hereda dos clases: Parent_1 y Parent_2. La clase Child_2 también hereda dos clases: Parent_2 y Parent_3. Otra clase Child_3 hereda tres clases: Child_1, Child_2 y Parent_3.
Ahora, con solo mirar esta herencia, es bastante difícil determinar el orden de resolución del método para la clase Child_3. Así que aquí está el uso real de __mro __-
Podemos ver que primero, el intérprete busca Child_3, luego Child_1 seguido de Parent_1, Child_2, Parent_2 y Parent_3 respectivamente.
3. Herencia multinivel
Por ejemplo, una clase_1 es heredada por una clase_2 y esta clase_2 también es heredada por clase_3 y este proceso continúa. Esto se conoce como herencia multinivel. Entendamos con un ejemplo:
class Parent: def f1(self): print("Function of parent class.") class Child_1(Parent): def f2(self): print("Function of child_1 class.") class Child_2(Child_1): def f3(self): print("Function of child_2 class.") obj_1 = Child_1() obj_2 = Child_2() obj_1.f1() obj_1.f2() print("n") obj_2.f1() obj_2.f2() obj_2.f3()
Aquí, la clase Child_1 hereda la clase Parent y la clase Child_2 hereda la clase Child_1. En este Child_1 tiene acceso a las funciones f1 () y f2 () mientras que Child_2 tiene acceso a las funciones f1 (), f2 () y f3 (). Si intentamos acceder a la función f3 () usando el objeto de la clase Class_1, se producirá un error que indica:
El objeto ‘Child_1’ no tiene atributo ‘f3’
obj_1.f3()
4- Herencia jerárquica
En esto, varias clases Child heredan una sola clase Parent. El ejemplo dado en la introducción de la herencia es un ejemplo de herencia jerárquica ya que las clases BMW y Audi heredan la clase Coche.
Para simplificar, veamos otro ejemplo:
class Parent: deff1(self): print("Function of parent class.") class Child_1(Parent): deff2(self): print("Function of child_1 class.") class Child_2(Parent): deff3(self): print("Function of child_2 class.") obj_1 = Child_1() obj_2 = Child_2() obj_1.f1() obj_1.f2() print('n') obj_2.f1() obj_2.f3()
Aquí dos clases secundarias heredan la misma clase principal. La clase Child_1 tiene acceso a las funciones f1 () de la clase Parent y a la función f2 () de sí misma. Mientras que la clase Child_2 tiene acceso a las funciones f1 () de la clase Parent y la función f3 () de sí misma.
5- Herencia híbrida
Cuando hay una combinación de más de una forma de herencia, se conoce como herencia híbrida. Será más claro después de este ejemplo:
class Parent: def f1(self): print("Function of parent class.") class Child_1(Parent): def f2(self): print("Function of child_1 class.") class Child_2(Parent): def f3(self): print("Function of child_2 class.") class Child_3(Child_1, Child_2): def f4(self): print("Function of child_3 class.") obj = Child_3() obj.f1() obj.f2() obj.f3() obj.f4()
En este ejemplo, dos clases ‘Child_1 ′ y’ Child_2 ‘se derivan de la clase base’ Parent ‘usando herencia jerárquica. Otra clase ‘Child_3’ se deriva de las clases ‘Child_1’ y ‘Child_2’ usando múltiples herencias. La clase ‘Child_3’ ahora se deriva mediante herencia híbrida.
Anulación de método
El concepto de anulación es muy importante en herencia. Otorga la habilidad especial al niño / subclases de proporcionar una implementación específica a un método que ya está presente en sus clases padre.
class Parent: def f1(self): print("Function of Parent class.") class Child(Parent): def f1(self): print("Function of Child class.") obj = Child() obj.f1()
Aquí, la función f1 () de la clase Child ha anulado la función f1 () de la clase Parent. Siempre que el objeto de la clase Child invoque f1 (), se ejecuta la función de la clase Child. Sin embargo, el objeto de la clase principal puede invocar la función f1 () de la clase principal.
obj_2 = Parent() obj_2.f1()
La función super ()
La función super () en Python devuelve un objeto proxy que hace referencia a la clase padre usando el súper palabra clave. Esta palabra clave super () es básicamente útil para acceder a los métodos anulados de la clase principal.
- En una jerarquía de clases con herencia única, súper ayuda a hacer referencia a las clases principales sin nombrarlas explícitamente, lo que hace que el código sea más fácil de mantener.
Por ejemplo-
class Parent: def f1(self): print("Function of Parent class.") class Child(Parent): def f1(self): super().f1() print("Function of Child class.") obj = Child() obj.f1()
Aquí, con la ayuda de super (). F1 (), se ha llamado al método f1 () de la superclase de la clase Child, es decir, la clase Parent sin nombrarla explícitamente.
Una cosa a tener en cuenta aquí es que la clase super () puede aceptar dos parámetrosLos "parámetros" son variables o criterios que se utilizan para definir, medir o evaluar un fenómeno o sistema. En diversos campos como la estadística, la informática y la investigación científica, los parámetros son fundamentales para establecer normas y estándares que guían el análisis y la interpretación de datos. Su adecuada selección y manejo son cruciales para obtener resultados precisos y relevantes en cualquier estudio o proyecto....: el primero es el nombre de la subclase y el segundo es un objeto que es una instancia de esa subclase. Veamos como
class Parent: def f1(self): print("Function of Parent class.") class Child(Parent): def f1(self): super( Child, self ).f1() print("Function of Child class.") obj = Child() obj.f1()
El primer parámetro se refiere a la subclase Niño, mientras que el segundo parámetro se refiere al objeto de Child que, en este caso, es uno mismo. Puede ver que el resultado después de usar super () y super (Child, self) es el mismo porque, en Python 3, super (Child, self) es equivalente a self ().
Ahora veamos un ejemplo más usando la función __init__.
class Parent(object): def__init__(self, ParentName): print(ParentName, 'is derived from another class.') class Child(Parent): def__init__(self, ChildName): print(name,'is a sub-class.') super().__init__(ChildName) obj = Child('Child')
Lo que hemos hecho aquí es que llamamos a la función __init__ de la clase Parent (dentro de la clase Child) usando super () .__ init __ (ChildName). Y como el método __init__ de la clase Parent requiere un argumento, se ha pasado como «ChildName». Entonces, después de crear el objeto de la clase Child, primero se ejecutó la función __init__ de la clase Child, y luego la función __init__ de la clase Parent.
- El segundo caso de uso es admitir herencias múltiples cooperativas en un entorno de ejecución dinámica.
class First(): def __init__(self): print("first") super().__init__() class Second(): def __init__(self): print("second") super().__init__() class Third(Second, First): def __init__(self): print("third") super().__init__() obj = Third()
La llamada super () encuentra el siguiente método en el MRO en cada paso, por lo que First y Second también deben tenerlo, de lo contrario, la ejecución se detiene al final de primero () .__ init__.Tenga en cuenta que la superclase de Primera y Segunda es Objeto.
Busquemos el MRO de Third () también-
Third.__mro__
El orden es Tercero> Segundo> Primero y el mismo es el orden de nuestra salida.
Notas finales
Para concluir, en este artículo he desarrollado el concepto de herencia en la programación orientada a objetos en Python. Cubrí varias formas de herencia y algunos de los conceptos comunes en la herencia, como la anulación de métodos y la función super ().
Espero que haya entendido los conceptos explicados en este artículo. Hágame saber en los comentarios a continuación si tiene alguna pregunta.