Home > Mobile >  Python inheritance Best way to merge info with parents
Python inheritance Best way to merge info with parents

Time:08-20

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?

CodePudding user response:

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}

CodePudding user response:

You can refer to the parent's attribute in the child.

class Frog(Animal):
    info = Animal.info   {'three': 3}
  • Related