What is the meaning of inheritance in Python?

Suppose you have the following situation.

#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); } 

As you can see, makeSpeak is a procedure that accepts a common Animal object. In this case, Animal is very similar to the Java interface, since it contains only a pure virtual method. makeSpeak does not know the nature of the animals that it receives. It simply sends a “talk” signal and leaves the last binding to take care of which method to call: either Cat :: speak () or Dog :: speak (). This means that with regard to makeSpeak, knowing which subclass is actually passed does not matter.

But what about Python? Let's see the code for the same case in Python. Please note that I try to be as similar as possible to the C ++ case for a 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) 

Now in this example you see the same strategy. You use inheritance to use the hierarchical concept of both Dogs and Cats that are Animals. But in Python there is no need for this hierarchy. It works equally well

 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) 

In Python, you can send a “talk” signal to any object you want. If the object is able to handle it, it will be executed, otherwise it will throw an exception. Suppose you add an Airplane class to both codes and send an Airplane object to makeSpeak. In the case of C ++, it will not compile, since Airplane is not a derived class of Animal. In the case of Python, it will throw an exception at runtime, which might even be the expected behavior.

On the other hand, suppose you add the MouthOfTruth class using the speak () method. In the case of C +, either you have to reorganize your hierarchy, or you have to define a different makeSpeak method to receive MouthOfTruth objects, or in java you can extract the behavior in CanSpeakIface and implement an interface for each. There are many solutions ...

As I would like to point out, I did not find the only reason to use inheritance in Python (except for frameworks and exception trees, but I assume that there are alternative strategies). you do not need to implement a basic hierarchy to do polymorphic work. If you want to use inheritance to reuse the implementation, you can do the same by holding back and delegating, with the added benefit that you can change at runtime, and you clearly define the interface of the contained without risking unintended side effects.

So, in the end, the question is: what is the point of inheritance in Python?

Edit : Thanks for the very interesting answers. Indeed, you can use it to reuse the code, but I am always careful when reusing the implementation. In general, as a rule, I make very shallow inheritance trees or not a tree at all, and if the functionality is shared, I will reorganize it as a general module procedure and then call it from each object. I see the advantage of having one single point of change (for example, instead of adding to Dog, Cat, Moose, etc., I just add to Animal, which is the main advantage of inheritance), but you can achieve the same with the delegation chain (for example, a la JavaScript). I am not saying this is better, though, is another way.

I also found a similar post in this regard.

+74
python inheritance oop
Jun 19 '09 at 23:28
source share
11 answers

You mean runtime utilization as a “redefining” inheritance, but I believe that inheritance has its merits as an approach to design and implementation, being an integral part of object-oriented design. In my humble opinion, the question of whether you can achieve something else is not very appropriate, because in fact you can code Python without classes, functions, etc., But the question is how well thought out, reliable and readable your code will be.

I can give two examples where inheritance is the right approach, in my opinion, I am sure that there are more of them.

First, if you program correctly, your makeSpeak function may want to verify that its input is indeed Animal, and not only that it can "speak", in which case the most elegant method would be to use inheritance. Again, you can do it in other ways, but what is the beauty of an object-oriented design with inheritance - your code "really" checks if the input is "animal".

Secondly, and obviously simpler, encapsulation is another integral part of object-oriented design. This becomes relevant when the ancestor has data members and / or non-abstract methods. Take the following stupid example in which the ancestor has a function (talk_twice) that calls an abstract function:

 class Animal(object): def speak(self): raise NotImplementedError() def speak_twice(self): self.speak() self.speak() class Dog(Animal): def speak(self): print "woff!" class Cat(Animal): def speak(self): print "meow" 

Assuming that "speak_twice" is an important feature, you do not want to encode it in both Dog and Cat, and I'm sure you can extrapolate this example. Of course, you can implement a stand-alone Python function that will accept some object with a duck type, check if it has a speaking function and call it twice, but this is both non-elementary and missing number 1 (confirm it as Animal). Worse, and to strengthen the Encapsulation example, what if a member function in a descendant class wanted to use "speak_twice" ?

Even clearer if the ancestor class has a data element, for example, "number_of_legs" , which is not used by abstract methods in the ancestor, such as "print_number_of_legs" , but is initiated in the constructor of the descendant class (for example, Dog initialize it with 4, whereas Snake will initialize it with 0).

Again, I'm sure there are endless examples, but basically every (fairly large) software based on an object-oriented design will require inheritance.

+79
Jun 19 '09 at 23:35
source share
— -

Inheritance in Python is all about code reuse. Factor common functionality into a base class and implement various functionality in derived classes.

+11
Jun 20 '09 at 4:51
source share

Inheritance in Python is more convenient than anything else. I believe that it is best used to provide the class with "default behavior".

Indeed, there is a significant community of Python developers who generally object to using inheritance. Whatever you do, don't just overdo it. Having an overly complex class hierarchy is a surefire way to get the designation “Java programmer,” and you just can't do it. :-)

+9
Jun 20 '09 at 3:44
source share

I think the point of inheritance in Python is not to compile the code, this is for the real reason for inheritance, which extends the class to another child class and redefines the logic in the base class. However, duck typing in Python makes the concept of an “interface” useless because you can simply check if a method exists before the call, without having to use an interface to limit the structure of the class.

+8
Jun 19 '09 at 23:34
source share

I think it is very difficult to give a meaningful, concrete answer with such abstract examples ...

To simplify, there are two types of inheritance: interface and implementation. If you need to inherit an implementation, then python is no different from statically typed OO languages ​​like C ++.

Interface inheritance is where the big difference is, with the fundamental implications for developing your software in my experience. Languages ​​like Python do not force you to use inheritance in this case, and avoiding inheritance is a good point in most cases, because it is very difficult to fix the wrong design choice there later. This is a well-known point raised in any good OOP book.

There are cases where using inheritance for interfaces is advisable in Python, for example, for plug-ins, etc. In these cases, Python 2.5 and below does not have a “built-in” elegant approach and several large frameworks developed by their own solutions (zope, trac, twister). Python 2.6 and above ABC classes to solve this problem .

+6
Jun 20 '09 at 3:31
source share

In C ++ / Java / etc, polymorphism is caused by inheritance. Abandon this erroneous faith, and dynamic languages ​​are revealed to you.

Essentially, in Python there is no interface like "understanding that certain methods are callable." Pretty tame, exciting and academic, no? This means that since you call "talk," you clearly expect the object to have a "talk" method. Just huh? This is very Liskov-ian in that class users define its interface, a good design concept that leads you to a healthier TDD.

So what remains is that another poster politely avoided talking, a trick for exchanging codes. You can write the same behavior in each "child" class, but that will be redundant. It is easier to inherit or mix functions that are invariant over the inheritance hierarchy. Smaller DRY-er code is better at all.

+5
Jun 20 '09 at 1:01
source share

It is not the inheritance that duck typing makes senseless, it interacts - like the one you chose when creating the entire abstract class of animals.

If you used a class of animals that introduced some kind of real behavior for their descendants to use it, then the classes of dogs and cats that introduced some kind of extra behavior would be the reason for both classes. This is only if the ancestor class does not contribute any actual code to the descendant classes, that your argument is correct.

Since Python can directly know the capabilities of any object, and since these capabilities change outside the class definition, the idea of ​​using a clean abstract interface to “tell” the program what methods can be called is somewhat meaningless. But this is not the only, or even the main, point of inheritance.

+5
Oct 15 '09 at 22:28
source share

You can bypass inheritance in Python and almost any other language. It's all about code reuse and code simplification.

Just a semantic trick, but after creating your classes and base classes, you don’t even need to know what is possible with your object to see if you can do it.

Say you have d, which is the Dog that has classified Animal.

 command = raw_input("What do you want the dog to do?") if command in dir(d): getattr(d,command)() 

If everything the user enters is available, the code will work properly.

Using this, you can create any combination of the Mammal / Reptile / Bird hybrid monster that you want, and now you can say "Bark!". during the flight and sticking out his forked tongue, and he will cope with it correctly! Enjoy it!

+1
Jun 24 '09 at 23:40
source share

I don’t see much point in inheritance.

Every time I ever used inheritance in real systems, I was burned because it led to a confused network of dependencies, or I just realized over time that I would be much better off without it. Now I am avoiding this as much as possible. I just never use it.

 class Repeat: "Send a message more than once" def __init__(repeat, times, do): repeat.times = times repeat.do = do def __call__(repeat): for i in xrange(repeat.times): repeat.do() class Speak: def __init__(speak, animal): """ Check that the animal can speak. If not we can do something about it (eg ignore it). """ speak.__call__ = animal.speak def twice(speak): Repeat(2, speak)() class Dog: def speak(dog): print "Woof" class Cat: def speak(cat): print "Meow" >>> felix = Cat() >>> Speak(felix)() Meow >>> fido = Dog() >>> speak = Speak(fido) >>> speak() Woof >>> speak.twice() Woof >>> speak_twice = Repeat(2, Speak(felix)) >>> speak_twice() Meow Meow 

James Gosling once asked a question at a press conference: "If you could come back in a different way, what would you leave?" His answer was “Classes,” to which there was a laugh. Nevertheless, he was serious and explained that in reality it was not classes, but a problem, but inheritance.

I see it as a drug addiction - it gives you a quick fix, which is good, but in the end it confuses you. By this, I mean it's a convenient way to reuse code, but it leads to an unhealthy relationship between the child and parent classes. Changes to the parent can damage the child. The child depends on the parent for a certain functionality and cannot change this functionality. Therefore, the functionality provided by the child is also tied to the parent - you can only have both.

It is best to provide one client class for an interface that implements the interface using the functionality of other objects that were compiled during construction. By doing this through well-designed interfaces, you can eliminate all the couplings, and we provide a very complex API (this is nothing new - most programmers already do this, this is not enough). Please note that the executing class should not just reveal the functionality, otherwise the client should just use the compiled classes directly - he should do something new by combining this functionality.

There is an argument in the inheritance camp that the implementation of pure delegation suffers, because they require many “glue” methods that simply pass values ​​through the delegation chain. However, it is just to rethink a design similar to inheritance using delegation. Programmers with too many years of experience with inheritance are especially vulnerable to falling into this trap, because, without realizing it, they will think about how they will implement something using inheritance, and then convert it to a deletion.

The correct separation of problems, such as the code above, does not require glue methods, since each step actually adds value, so they are not “glue” methods at all (if they do not add value, the design is wrong).

It comes down to the following:

  • For reusable code, each class should only do one thing (and do it well).

  • Inheritance creates classes that do more than one, because they mix with the parent classes.

  • Therefore, using inheritance makes classes difficult to reuse.

+1
Jul 01 '09 at 20:55
source share

Another small point is the op 3'rd example, you cannot call isinstance (). For example, passing your third example to another object that accepts the type of "Animal", it is talked about. If you do this, you will not have to check the type of dog, type of cat, etc. Not sure if the instance check is really "Pythonic" due to late binding. But then you will have to implement some way that AnimalControl does not try to throw Cheeseburger types into the truck, because the Cheeseburgers do not speak.

 class AnimalControl(object): def __init__(self): self._animalsInTruck=[] def catachAnimal(self,animal): if isinstance(animal,Animal): animal.speak() #It upset so it speak's/maybe it should be makesNoise if not self._animalsInTruck.count <=10: self._animalsInTruck.append(animal) #It then put in the truck. else: #make note of location, catch you later... else: return animal #It not an Animal() type / maybe return False/0/"message" 
+1
Jul 11 2018-12-12T00:
source share

Classes in Python are basically just ways to group multiple functions and data. They differ from classes in C ++, etc.

I basically saw inheritance used to override superclass methods. For example, perhaps using Python'ish inheritance would be ...

 from world.animals import Dog class Cat(Dog): def speak(self): print "meow" 

Of course, cats are not a type of dog, but I have this (third-party) class Dog , which works fine, except for the speak method, which I want to redefine - it saves re-introducing the whole class, it just meows. Again, until Cat is a type of Dog , but the cat inherits many attributes.

A more correct (practical) example of overriding a method or attribute is how you modify the user agent for urllib. You are basically a subclass of urllib.FancyURLopener and change the version attribute ( from the documentation ):

 import urllib class AppURLopener(urllib.FancyURLopener): version = "App/1.7" urllib._urlopener = AppURLopener() 

Other exceptions are used for exceptions when inheritance is used more “correctly”:

 class AnimalError(Exception): pass class AnimalBrokenLegError(AnimalError): pass class AnimalSickError(AnimalError): pass 

.. you can catch AnimalError to catch all the exceptions that inherit from it, or specific, like AnimalBrokenLegError

0
Jun 19 '09 at 23:52
source share



All Articles