One of the answers to a previous question I asked suggests the use of a metaclass.
class DogType(type):
def __init__(cls, name, bases, attrs):
""" this is called at the Dog-class creation time. """
if not bases:
return
#pick the habits of direct ancestor and extend it with
#this class then assign to cls.
if "habits" in attrs:
base_habits = getattr(bases[0], "habits", [])
cls.habits = base_habits + cls.habits
class Dog(metaclass=DogType):
habits = ["licks butt"]
def __repr__(self):
return f"My name is {self.name}. I am a {self.__class__.__name__} %s and I like to {self.habits}"
def __init__(self, name):
""" dog instance can have all sorts of instance variables"""
self.name = name
class Sheperd(Dog):
habits = ["herds sheep"]
class GermanSheperd(Sheperd):
habits = ["bites people"]
class Poodle(Dog):
habits = ["barks stupidly"]
class StBernard(Dog):
pass
for ix, cls in enumerate([GermanSheperd, Poodle, StBernard]):
name = f"dog{ix}"
dog = cls(name)
print(dog)
However this throws an error:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I like this solution, however I also really need class Dog
to behave like a metaclass such that I can define abstract methods in Dog
that will need to propagate in all subclasses. This could be a method like def bark()
which all sub-dogs would need to implement...
How do I get Dog
to be both a metaclass implementing the functionality in DogType
, but also an Abstract class of its own accord which restricts how subclasses are instantiated and run?