Let there be an abstract class Animal
which is extended and implemented by class Dog
and class Cat
.
class Animal:
def speak(self):
raise NotImplementedError
... # 50 other methods with implementation and another 40 without implementation (abstract, headers only)
class Dog(Animal):
def speak(self):
return "ruff"
... # 40 more implemented methods
class Cat(Animal):
def speak(self):
return "purr"
... # 40 more implemented methods
There is also a bunch of functionality that can turn Animals
into RoboAnimals
, which causes every Animal
type to say "beep boop" before anything whenever they speak
.
How should one implement both a class RoboDog
and a class RoboCat
while avoiding duplicating code? Neither Dog
, Cat
, or Animal
can be manipulated.
I've tried using another class
-- RoboAnimal
-- that extends Animal
in order to cover for 50 basic Animal
methods, but Animal
has 40 other abstract methods that need appropriate implementation (Dog
/Cat
). If I use composition, and simply wrap a Dog
or Cat
instance, I'd still have to make sure that all Animal
methods called on this object behave accordingly to whether the flying animal is actually a Dog
or a Cat
.
Just to be clear, a RoboDog
returns "beep boop ruff"
on .speak()
calls and otherwise behaves like a Dog
, and likewise with Cat
("beep boop purr"
).
Can you do that in Python 3.10?
EDIT: My attempts at solving the problem:
#1
class RoboDog(Dog):
def speak(self):
return "beep boop " super().speak()
class RoboCat(Cat):
def speak(self):
return "beep boop " super().speak()
# damn, I've just duplicated the code...
# what if adding robotic functionality
# to animals took hundreds of lines of
# code, now that would be a hassle to maintain
#2
class RoboAnimal(Animal):
def speak(self):
return "beep boop " super().speak()
# oh snap, super().speak() raises an error :(
#3
class RoboAnimal(Animal):
def __init__(self, animal_cls, ...):
super().__init__(...)
self.wrapped_animal = animal_cls(...)
def speak(self):
return "beep boop " self.wrapped_animal.speak()
# now this is epic, but none of the 40 abstract methods work now
CodePudding user response:
You can create a class that overrides only one of the methods you need, and insert it in the right order in the inheritance tree. This is called a mixin:
class Animal:
pass
class Dog(Animal):
def speak(self):
return 'woof!'
class RoboAnimal:
def speak(self):
return 'beep boop ' super().speak()
class RoboDog(RoboAnimal, Dog):
pass
print(RoboDog().speak())
Notice that RoboDog.speak
calls super().speak
. This means that if you don't put a valid instance of Animal
in the inheritance chain after it, it will crash if it is called. RoboAnimal
does not need to inherit from Animal
because it serves an entirely different purpose. In fact I would probably call the class something like RoboMixin
to avoid confusion.
In general, the order of base classes in multiple inheritance is important. For example, in the following case, the mixin method would never be called because Dog.speak
never calls super().speak
:
class WrongRoboDog(Dog, RoboAnimal):
pass