Reputation: 29
Imagine we have a class Animal with a class attribute info
, which is a dictionary. There is a class Frog which inherits from Animal and also has a class attribute info
. But the attribute info
of the Frog class must also include the Animal info.
class Animal:
info = {'one':1, 'two':2}
class Frog(Animal):
info = {'three':3}
assert 'three' in Frog.info
I can use @property
class Frog(Animal):
_info = {'three':3}
@property
def info(self):
return self._info | Frog.info
But this is just fragile. Do the large Python library includes any Class that doesn't overwrite the Class attributes?
Upvotes: 0
Views: 357
Reputation: 33833
If you want the info
values to be automatically merged by subclasses, you will need to use a metaclass to achieve this.
The metaclass is code which can modify the class definition, so it can look at the value of info
on the parent class and the value of info
in the sub-class as it is being defined ... and it can merge them and set the result of that as the value of info
in the resulting sub-class.
It would look like this:
class MergeInfoMetaclass(type):
def __new__(metacls, name, bases, attrs):
base_info = {}
for base in bases:
try:
base_info.update(base.info)
except AttributeError:
continue
try:
info = attrs["info"]
except KeyError:
pass
else:
attrs["info"] = base_info | info
return super().__new__(metacls, name, bases, attrs)
class Animal(metaclass=MergeInfoMetaclass):
info = {'one': 1, 'two': 2}
class Frog(Animal):
info = {'three': 3}
class GoldenTreeFrog(Frog):
info = {'four': 4}
assert Animal.info == {'one': 1, 'two': 2}
assert Frog.info == {'one': 1, 'two': 2, 'three': 3}
assert GoldenTreeFrog.info == {'one': 1, 'two': 2, 'three': 3, 'four': 4}
You can find more info about Python metaclasses here https://realpython.com/python-metaclasses/#custom-metaclasses
Basically, when Python is reading your class definition, like:
class Animal(metaclass=MergeInfoMetaclass):
info = {'one': 1, 'two': 2}
Python takes the details of the new class (the name, base classes and class attrs, which include the methods too) and passes them to the metaclass. At this point the Animal
class does not exist yet. The metaclass is responsible for creating the new class object (meaning the class itself and not an instance of the class).
Upvotes: 2
Reputation: 780879
You can refer to the parent's attribute in the child.
class Frog(Animal):
info = Animal.info + {'three': 3}
Upvotes: 0