Adrian
Adrian

Reputation: 163

Implementing inherited method in parent class

I'm attempting to understand Python inheritence and below class CarWithBrakes inherits from class Car :

class Car :
    def __init__(self , wheels):
        self.wheels = wheels
        self.jsonTransform = {}
        self.jsonTransform['wheels'] = wheels
        
    def toJson(self):
        return self.jsonTransform
    
    def get_wheels(self):
        return self.wheels
    
class CarWithBrakes(Car):
    
    def __init__(self , car, brakes):
        self.car = car
        self.brakes = brakes

    def toJson(self):
        self.jsonTransform = {}
        self.jsonTransform['wheels'] = self.car.wheels
        self.jsonTransform['brakes'] = self.brakes
        return self.jsonTransform
    
c = Car("wheels")
print(c.toJson())

b = CarWithBrakes(c , "brakes")
print(b.toJson())
print(b.get_wheels())

Running this code produces:

{'wheels': 'wheels'}
{'wheels': 'wheels', 'brakes': 'brakes'}

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-62-9b4b5598414b> in <module>
     30 b = CarWithBrakes(c , "brakes")
     31 print(b.toJson())
---> 32 print(b.get_wheels())

<ipython-input-62-9b4b5598414b> in get_wheels(self)
     11 
     12     def get_wheels(self):
---> 13         return self.wheels
     14 
     15 class CarWithBrakes(Car):

Shouldn't wheels attribute be available as CarWithBrakes inherits from Car?

Upvotes: 4

Views: 50

Answers (2)

poke
poke

Reputation: 387547

In Python, you will have to call the base constructor if you want that to execute for your derived type. You can do this using super() which allows you to access the base type.

So your CarWithBrakes should look like this:

class CarWithBrakes(Car):
    def __init__(self, wheels, brakes):
        # call base implementation
        super().__init__(wheels)        

        # no need to set `self.wheels` since that is done in the base
        # but do set the `brakes` which the base class does not know about
        self.brakes = brakes

You also don’t want to pass in a car instance but instead create a CarWithBrakes directly. A CarWithBrakes is a Car; but a CarWithBrakes does not contain another Car.

Upvotes: 2

timgeb
timgeb

Reputation: 78650

There are two issues here.

CarWithBrakes does override the __init__ method of Car. In the overridden method, the wheels attribute is not set. Usually, you delegate work you want to share with the child class (such as setting the wheels attribute) to the child class initializer via super().__init__(...).

Second, you are unnecessarily mixing inheritance and aggregation. A CarWithBrakes is-a car by inheritance, there's no reason to pass a Car instance to hold onto in CarWithBrakes.__init__.

Upvotes: 4

Related Questions