Home > Software engineering >  Inheritance from two parents
Inheritance from two parents

Time:10-23

I am struggling with the inheritance from two parents. I want to inherit from both the "super car" and the "cargo car" in order to be able to create a "super cargo car". When I call the code from below, I get:

"TypeError: __init __ () missing 1 required positional argument: 'capacity'"

class Car:

    def __init__(self, brand, colour):
        self.brand = brand
        self.colour = colour


class SuperCar(Car):

    def __init__(self, brand, colour, max_speed):
        super().__init__(brand, colour)
        self.max_speed = max_speed

    def introduce_yourself(self):
        statement = f"My colour is {self.colour} and my max speed is {self.max_speed}"
        return statement


class CargoCar(Car):

    def __init__(self, brand, colour, capacity):
        super().__init__(brand, colour)
        self.capacity = capacity

    def introduce_yourself(self):
        statement = f"My colour is {self.colour} and my capacity is {self.capacity} KG"
        return statement


class SuperCargoCar(SuperCar, CargoCar):

    def __init__(self, brand, colour, max_speed, capacity ):
        super().__init__(brand, colour, max_speed)
        self.capacity = capacity

    def introduce_yourself(self):
        super().introduce_yourself()
        statement = f'My colour is {self.colour}, my max speed is {self.max_speed} ' \
                    f'and my capacity is {self.capacity} KG'
        return statement


super_cargo_car = SuperCargoCar(brand="Volvo", colour="Green", max_speed=200, capacity=5000)
print(super_cargo_car.introduce_yourself())```

CodePudding user response:

As both of your SuperCar and CargoCar classes inherit from Car class it results in an ambiguous mro. Fix it the following way:

class Car:

    def __init__(self, brand, colour):
        self.brand = brand
        self.colour = colour


class SuperCar(Car):

    def __init__(self, brand, colour, max_speed):
        super().__init__(brand, colour)
        self.max_speed = max_speed

    def introduce_yourself(self):
        statement = f"My colour is {self.colour} and my max speed is {self.max_speed}"
        return statement


class CargoCar(Car):

    def __init__(self, brand, colour, capacity):
        super().__init__(brand, colour)
        self.capacity = capacity

    def introduce_yourself(self):
        statement = f"My colour is {self.colour} and my capacity is {self.capacity} KG"
        return statement


class SuperCargoCar(SuperCar):    
    """you need not inherit from CargoCar as it has got only one extra 
       feature i.e. capacity which could be added to the new class directly
       as inheriting this will lead to an absurd mro which will cause Python 
       to throw an exception"""

    def __init__(self, brand, colour, max_speed, capacity):
        SuperCar.__init__(self,brand, colour, max_speed)
        self.capacity = capacity
        #CargoCar.__init__(self,brand,colour,capacity)
        

    def introduce_yourself(self):
        statement = f'My colour is {self.colour}, my max speed is {self.max_speed} ' \
                    f'and my capacity is {self.capacity} KG'
        return statement

super_cargo_car = SuperCargoCar(brand="Volvo", colour="Green", max_speed=200, capacity=5000)
print(super_cargo_car.introduce_yourself())

CodePudding user response:

As multiple inheritance in this case would create multiple of the same member (max_speed and capacity) which all kind of Car has anyway I would suggest to refactor your code to something like this:

class Car:

    def __init__(self, brand, colour, max_speed=None,capacity=None):
        self.brand = brand
        self.colour = colour
        self.max_speed = max_speed
        self.capacity = capacity

    def introduce_yourself(self):
        return f"I am a(n) {self.__class__.__name__} of {self.brand}."   f" My colour is {self.colour}."

class SuperCar(Car):

    def __init__(self, brand, colour, max_speed):
        super().__init__(brand, colour, max_speed=max_speed)

    def introduce_yourself(self):
        return super().introduce_yourself()   f" My max speed is {self.max_speed}."


class CargoCar(Car):

    def __init__(self, brand, colour, capacity):
        super().__init__(brand, colour,capacity=capacity)

    def introduce_yourself(self):
        return super().introduce_yourself()   f" My capacity is {self.capacity} kg."


class SuperCargoCar(Car):

    def __init__(self, brand, colour, max_speed, capacity ):
        super().__init__(brand, colour,max_speed=max_speed,capacity=capacity)

    def introduce_yourself(self):
        return super().introduce_yourself()   f" My max speed is {self.max_speed} and my capacity is {self.capacity} kg."

class Factory:

    def __init__(self, brand):
        self.brand = brand

    def manufacture(self, colour, **kwargs):
        kwargs['colour'] = colour
        kwargs['brand'] = self.brand
        if all(k in kwargs for k in ['max_speed','capacity']):
            return SuperCargoCar(**kwargs)
        if all(k in kwargs for k in ['max_speed']):
            return SuperCar(**kwargs)
        if all(k in kwargs for k in ['capacity']):
            return CargoCar(**kwargs)
        return Car(**kwargs)

factory = Factory(brand='Volvo')
car = factory.manufacture(colour="green", max_speed=200, capacity=5000)
print(car.introduce_yourself())

Each derived car will inherit all members and methods of the Car class and only set the values which are specific to that type of car. I also introduced a Factory class that will decide based on the arguments which derived Car to manufacture. I also moved the brand to the factory so that all cars made there will have the same brand, but this is really up to you how you want to deal with that, I just showed some additional things you could make with this kind of structure.

  • Related