Suppose you have a concrete class
class Knight(object):
def __init__(self, name):
self._name = name
def __str__(self):
return "Sir {} of Camelot".format(self.name)
Now it happens that the class hierarchy has to change. Knight
should become an abstract base class, with a bunch of concrete subclasses for knights of various castles. Easy enough:
class Knight(metaclass=ABCMeta): # Python 3 syntax
def __str__(self):
return "Sir {} of {}".format(self.name, self.castle)
@abstractmethod
def sing():
pass
class KnightOfTheRoundTable(Knight):
def __init__(self, name):
self.name = name
@property
def castle(self):
return "Camelot"
@staticmethod
def sing():
return ["We're knights of the round table",
"We dance whenever we're able"]
But now all code that used Knight("Galahad")
to construct a Knight
is broken. We can instead keep Knight
as it is and introduce a BaseKnight
, but then code that checks for isinstance(x, Knight)
and should work on any knight may have to be changed to check for BaseKnight
instead.
How does one turn a concrete class into an abstract one, sparing both the constructor and the isinstance
checks?