Herencia de clase Python

Herencia de clase Python

Una característica de los lenguajes orientados a objetos es la herencia de clases. La relación de herencia es similar a la de reproducción humana. La clase heredada se llama clase base (también llamada clase padre) y la clase heredada se llama clase derivada (también llamada clase hija). Esta relación es como la relación padre-hijo de los seres humanos.

La herencia de una clase ilustra la relación directa entre diferentes clases. La clase derivada reutiliza el código de la clase base y también hereda las propiedades y métodos de la clase base. La sintaxis de una definición de clase derivada es la siguiente:

Definición de clase derivada

class DerivedClassName(BaseClassName):
    Declaración 1
    ...
    Declaración n
A continuación escribimos un ejemplo de herencia basado en esta sintaxis:
class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height

    def look(self):
        print(self.name, 'is looking')

    def walk(self):
        print(self.name, 'is walking')


class Teacher(Person):
    def __init__(self, name, age, height):
        super().__init__(name, age, height)

    def teach(self):
        print(self.name, 'is teaching')


class Student(Person):
    def __init__(self, name, age, height):
        super().__init__(name, age, height)

    def learn(self):
        print(self.name, 'is learning')


if __name__ == '__main__':
    teacher = Teacher('Tom', 31, 178)
    s1 = Student('Jim', 12, 160)
    s2 = Student('Kim', 13, 162)

    teacher.look()
    teacher.walk()
    teacher.teach()
    print('==='*5)

    s1.look()
    s1.walk()
    s1.learn()
    print('==='*5)

    s2.look()
    s2.walk()
    s2.learn()
Definimos una clase base Person , que tiene tres atributos: nombre, edad y altura, así como look(), walk() . Deriva dos clases: Teacher y Student , que heredan las propiedades de name, age, height , y heredan los métodos look(), walk() . Pero tienen sus propios métodos únicos, el Teacher puede teach() y el Student puede learn() .
Ejecute este código de ejemplo para obtener la siguiente información:
Tom is looking
Tom is walking
Tom is teaching
===============
Jim is looking
Jim is walking
Jim is learning
===============
Kim is looking
Kim is walking
Kim is learning
Las definiciones de clase derivadas se ejecutan de la misma manera que las clases base.La clase base se recuerda cuando se construye el objeto de clase. Esta información se utilizará para resolver la referencia de propiedad: si la propiedad solicitada no se encuentra en la clase, la búsqueda se remitirá a la clase base para su búsqueda. Si la propia clase base se deriva de alguna otra clase, esta regla se aplicará recursivamente.
La creación de instancias de una clase derivada crea una nueva instancia de la clase. La referencia del método se analizará de la siguiente manera: busque el atributo de clase correspondiente. Si el método de búsqueda no se encuentra en la clase derivada, se buscará en la clase base. Si la clase base se deriva de otras clases, la regla será recursiva. Aplicacion La referencia del método surte efecto si se encuentra un objeto de función.
Por ejemplo, el Teacher no define look() . Cuando llamamos al método teacher.look() , encontramos y llamamos look() en su clase base Person .

Método de clase base de sobrecarga

Las clases derivadas pueden anular los métodos de la clase base. La sobrecarga se está redefiniendo. Si un método de la clase base se redefine en la clase derivada, entonces el método sobrecargado de la clase derivada anula el método del mismo nombre en la clase base.
Por ejemplo, cuando definimos un Student , podemos anular el método walk() para tener la función de Student :
class Student(Person):
    def __init__(self, name, age, height):
        super().__init__(name, age, height)

    def learn(self):
        print(self.name, 'is learning')

    def walk(self):
        print('Student:', self.name, 'is walking')
Cuando ejecuta s1.walk() nuevamente, se imprime la siguiente información:
Student: Jim is walking
Python tiene dos funciones integradas que se pueden usar para verificar el mecanismo de herencia:
  • isinstance() verifica el tipo de una instancia: isinstance(obj, int) solo isinstance(obj, int) Verdadero si obj.__class__ es un int o una clase derivada de int .
  • issubclass() comprueba la relación de herencia de la clase: issubclass(bool, int)es True porque bool es una subclase de int . Sin embargo, issubclass(float, int) es False porque float no es una subclase de int .

Herencia múltiple

La herencia múltiple significa que una clase derivada se deriva de varias clases base y hereda todas sus propiedades y métodos. Su forma de definición es:
class DerivedClassName(Base1, Base2, Base3):
    Declaración 1
    ...
    Declaración 1
Para la mayoría de las aplicaciones, en el caso más simple, puede pensar que la búsqueda de atributos heredados de la clase padre es la primera en profundidad, de izquierda a derecha, y no buscará en la misma clase cuando haya una superposición en la jerarquía. Dos veces Por lo tanto, si un atributo no se encuentra en DerivedClassName, se buscará en Base1, luego (recursivamente) se buscará en la clase base de Base1, si no se encuentra allí, luego se buscará en Base2, y así sucesivamente.
La situación real es más complicada que esto, el orden de análisis del método se cambia dinámicamente para admitir llamadas coordinadas a super (). Este enfoque se denomina una llamada de método posterior en algunos otros lenguajes de herencia múltiple, y es más poderoso que una súper llamada en un idioma de herencia única.
Por ejemplo, queremos definir una clase de "asistente de maestro", que es un compañero de clase superior que ayuda a los maestros a enseñar. Él tiene las características de profesores y estudiantes, y podemos hacer que esta clase herede la "clase de profesor" y la "clase de estudiante".

Variable privada

Como dijimos en la sección anterior, no hay una "variable privada" en C ++ como C ++.Sin embargo, la mayoría del código de Python sigue dicha convención (solo una convención, pero es importante): un nombre con un guión bajo (por ejemplo: _name ) debe actuar como una parte no parcial de la API (ya sea una función, un método o datos) Miembro). Esto debe considerarse un detalle de la implementación y se puede cambiar sin previo aviso.
Dado que existen escenarios de uso válidos para los miembros privados de una clase (por ejemplo, evitar nombres que entren en conflicto con los nombres definidos por las subclases), existe un soporte limitado para dichos mecanismos, llamado reescritura de nombres . Cualquier __name de la forma __name (con al menos dos guiones bajos de prefijo, como máximo un subrayado de sufijo) será reemplazado por _classname__name , donde classname es el nombre de clase actual con el subrayado de prefijo eliminado. Esta reescritura no tiene en cuenta la posición de sintaxis del identificador, siempre que aparezca dentro de la definición de clase.
La reescritura de nombres ayuda a las subclases a anular los métodos sin interrumpir las llamadas de métodos en clase. Por ejemplo:
class MyList:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # Copia "update ()" al método privado

class MyListSubclass(MyList):

    def update(self, keys, values):
        # Recargar update()
        # Pero no destruirá __init__()
        for item in zip(keys, values):
            self.items_list.append(item)
En este ejemplo, incluso si MyListSubclass introduciendo un __update identifier, no saldrá mal, porque se reemplazará con _MyList__update en la clase MyListSubclass y MyListSubclass en la clase MyListSubclass .
Las reglas de reescritura están diseñadas principalmente para evitar conflictos accidentales, aún es posible acceder o modificar variables que se consideran privadas.Esto incluso puede ser útil en situaciones especiales, como en un depurador.
Tenga en cuenta que el código pasado a exec () o eval () no trata el nombre de clase de la clase que llama como la clase actual, esto es similar al efecto de una declaración global, por lo que este efecto se limita al código que se compila con el código de bytes al mismo tiempo. Las mismas restricciones se aplican a getattr (), setattr () y delattr (), así como a las referencias directas a dict .

Resumen

La herencia de una clase encarna la relación de la clase. Las propiedades y los métodos de la clase base pueden ser heredados por la clase derivada, y la clase derivada puede anular el método de la clase base. Las clases derivadas pueden heredar una clase base por separado o varias clases base. Las clases de Python no tienen variables privadas en el verdadero sentido, y el soporte para las variables privadas está limitado por las convenciones y los cambios de nombre.

留言