Je m'excuse si cette question est longue. Cela faisait partie d'un post de blog je l'ai fait il y a quelques temps, et un lecteur m'a proposé de le publier sur stackoverflow. J'ai coupé un peu.
Supposons que vous avez la situation suivante
#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);
}
Comme vous pouvez le voir, makeSpeak est une routine qui accepte un générique Animal objet. Dans ce cas, l'Animal est assez similaire à une interface Java, comme elle ne contient qu'une méthode virtuelle pure. makeSpeak ne connaît pas la nature de l'Animal, elle est adoptée. Il envoie le signal "parler" et laisse la liaison tardive pour prendre soin de la méthode à appeler: Cat::parler() ou Chien::parler(). Cela signifie que, dans la mesure du makeSpeak est concerné, la connaissance de ce qui sous-classe est réellement passé n'est pas pertinent.
Mais qu'en Python? Nous allons voir le code pour le même cas en Python. Veuillez noter que j'essaie d'être aussi semblable que possible à la C++ cas pour un moment:
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)
Maintenant, dans cet exemple, vous voyez la même stratégie. Vous utiliser l'héritage pour tirer parti de la conception hiérarchique de les Chiens et les Chats étant des Animaux. Mais en Python, il n'y a pas besoin de cette hiérarchie. Ceci fonctionne aussi bien
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)
En Python, vous pouvez envoyer le signal "parler" à n'importe quel objet que vous voulez. Si l'objet est en mesure de traiter avec elle, il sera exécuté, sinon il va lever une exception. Supposez que vous ajoutez une classe d'Avion pour les deux codes, et de soumettre un Avion de l'objet à makeSpeak. Dans le C++ cas, il ne compile pas, comme l'Avion n'est pas une classe dérivée de l'Animal. Dans le Python cas, il déclenche une exception lors de l'exécution, qui pourrait même être un comportement attendu.
De l'autre côté, supposons que vous ajoutez un MouthOfTruth classe avec une méthode parle(). Dans le C++, vous aurez à refactoriser votre hiérarchie, ou vous aurez à définir une autre makeSpeak méthode d'accepter MouthOfTruth objets, ou en java, vous pourrez extraire le comportement dans un CanSpeakIface et de mettre en œuvre l'interface pour chaque. Il existe beaucoup de solutions...
Ce que je voudrais souligner, c'est que je n'ai pas trouvé une seule raison encore utiliser l'héritage en Python (à l'exception des cadres et des arbres des exceptions, mais je suppose que les stratégies alternatives existent). vous n'avez pas besoin de mettre en œuvre une base de dérivés de la hiérarchie pour effectuer polymorphically. Si vous souhaitez utiliser l'héritage pour la réutilisation de la mise en œuvre, vous pouvez faire la même chose par le biais de confinement et de délégation, avec l'avantage supplémentaire que vous pouvez modifier au moment de l'exécution, et vous avez clairement définir l'interface de l'contenus, sans risquer de provoquer des effets secondaires indésirables.
Donc, en fin de compte, la question est: quel est le point de succession dans la de Python?
Edit: merci pour les réponses très intéressantes. En effet, vous pouvez l'utiliser pour la réutilisation de code, mais je suis toujours prudent lors de la réutilisation de mise en œuvre. En général, j'ai tendance à faire très peu profonde de l'héritage des arbres ou pas d'arbre, et si une fonctionnalité est bon je refactoriser un module commun de routine et ensuite appeler à partir de chaque objet. Je vois l'avantage d'avoir un seul point de changement (par exemple. au lieu d'ajouter de Chien, de Chat, de l'Orignal et ainsi de suite, je viens de l'ajouter à l'Animal, qui est le principal avantage de l'héritage), mais vous pouvez obtenir la même chose avec une délégation de la chaîne (par exemple. la JavaScript). Je ne dis pas que c'est mieux si, juste une autre façon.
J'ai aussi trouvé un poste similaire sur ce sujet.