¿Cuál es el punto de herencia en Python?

Supongamos que tienes la siguiente situación

<code>#include <iostream>

class Animal {
public:
    virtual void speak() = 0;
};

class Dog : public Animal {
    void speak() { std::cout << "woff!" <<std::endl; }
};

class Cat : public Animal {
    void speak() { std::cout << "meow!" <<std::endl; }
};

void makeSpeak(Animal &a) {
    a.speak();
}

int main() {
    Dog d;
    Cat c;
    makeSpeak(d);
    makeSpeak(c);
}
</code>

Como puedes ver, makeSpeak es una rutina que acepta un objeto Animal genérico. En este caso, Animal es bastante similar a una interfaz Java, ya que solo contiene un método virtual puro. makeSpeak no sabe la naturaleza del animal que pasa. Simplemente envía la señal "hablar" y deja el enlace tardío para ocuparse de qué método llamar: Cat :: speak () o Dog :: speak (). Esto significa que, en lo que respecta a makeSpeak, el conocimiento de qué subclase se pasa realmente es irrelevante.

Pero ¿qué pasa con Python? Veamos el código para el mismo caso en Python. Tenga en cuenta que trato de ser lo más parecido posible al caso de C ++ por un momento:

<code>class Animal(object):
    def speak(self):
        raise NotImplementedError()

class Dog(Animal):
    def speak(self):
        print "woff!"

class Cat(Animal):
    def speak(self):
        print "meow"

def makeSpeak(a):
    a.speak()

d=Dog()
c=Cat()
makeSpeak(d)
makeSpeak(c)
</code>

Ahora, en este ejemplo ves la misma estrategia. Usted utiliza la herencia para aprovechar el concepto jerárquico de que tanto los perros como los gatos son animales. Pero en Python, no hay necesidad de esta jerarquía. Esto funciona igual de bien

<code>class Dog:
    def speak(self):
        print "woff!"

class Cat:
    def speak(self):
        print "meow"

def makeSpeak(a):
    a.speak()

d=Dog()
c=Cat()
makeSpeak(d)
makeSpeak(c)
</code>

En Python puede enviar la señal "hablar" a cualquier objeto que desee. Si el objeto es capaz de tratar con él, se ejecutará, de lo contrario generará una excepción. Supongamos que agrega un avión de clase a ambos códigos y envía un objeto de avión a makeSpeak. En el caso de C ++, no se compilará, ya que Airplane no es una clase derivada de Animal. En el caso de Python, generará una excepción en el tiempo de ejecución, que incluso podría ser un comportamiento esperado.

En el otro lado, suponga que agrega una clase MouthOfTruth con un método speak (). En el caso de C ++, tendrá que refactorizar su jerarquía, o tendrá que definir un método makeSpeak diferente para aceptar objetos MouthOfTruth, o en java podría extraer el comportamiento en un CanSpeakIface e implementar la interfaz para cada uno. Hay muchas soluciones ...

Lo que me gustaría señalar es que aún no he encontrado una sola razón para usar la herencia en Python (aparte de marcos y árboles de excepciones, pero supongo que existen estrategias alternativas). no es necesario implementar una jerarquía derivada de la base para realizar polimorfos. Si desea utilizar la herencia para reutilizar la implementación, puede lograr lo mismo a través de la contención y la delegación, con el beneficio adicional de que puede modificarla en el tiempo de ejecución, y define claramente la interfaz del contenido, sin correr el riesgo de efectos secundarios no deseados.

Entonces, al final, la pregunta es: ¿cuál es el punto de la herencia en Python?

Editar: gracias por las respuestas muy interesantes. De hecho, puede usarlo para reutilizar el código, pero siempre tengo cuidado al reutilizar la implementación. En general, tiendo a hacer árboles de herencia muy poco profundos o ningún árbol, y si una funcionalidad es común, la refactorizo ​​como una rutina de módulo común y luego la llamo desde cada objeto. Veo la ventaja de tener un solo punto de cambio (por ejemplo, en lugar de agregar a Dog, Cat, Moose, etc., solo agrego a Animal, que es la ventaja básica de la herencia), pero se puede lograr lo mismo con una cadena de delegación (ej. a la JavaScript). Sin embargo, no estoy diciendo que sea mejor, solo de otra manera.

Tambien encontreuna publicación similar referente a esto.

Respuestas a la pregunta(11)

Su respuesta a la pregunta