Search code examples
python-3.xpython-2.7oopinheritancesuper

How can I find the current base class in a classmethod invoked by super?


How can I find the current base class in a classmethod invoked by super?

  • Class B inherits from A
  • The code in both data methods must be the same and should not include a literal class reference like A or B

I want the method data to gather the _data values going up the base classes.

class A:
  _data = "A data"
  @classmethod
  def data(cls) -> list[str]:
    # gather data here too, we may have N number of inheritance classes so we should try to invoke super here too

class B(A):
  _data = "B data"
  @classmethod
  def data(cls) -> list[str]:
    # gather data here and invoke super to gather data from A also

Solution

  • One can get the current base class with super().__thisclass__ Using this solution we can write the below code which meets these requirements:

    • Class B inherits from A
    • The code in both data methods must be the same and should not include a literal class reference like A or B
    class A:
        _data = "A data"
        @classmethod
        def data(cls):
            super_instance = super()
            this_cls = super_instance.__thisclass__
            try:
                other_data = super_instance.data()
            except AttributeError:
                return [this_cls._data]
            return [this_cls._data] + other_data
    
    class B(A):
        _data = "B data"
        @classmethod
        def data(cls):
            super_instance = super()
            this_cls = super_instance.__thisclass__
            try:
                other_data = super_instance.data()
            except AttributeError:
                return [this_cls._data]
            return [this_cls._data] + other_data
    
    B.data()
    # ['B data', 'A data']
    

    Or one can refactor that into the shorter:

    class DataGatherer:
        @staticmethod
        def gather_data(super_instance):
            this_cls = super_instance.__thisclass__
            try:
                other_data = super_instance.data()
            except AttributeError:
                return [this_cls._data]
            return [this_cls._data] + other_data
    
    
    class A(DataGatherer):
        _data = "A data"
        @classmethod
        def data(cls):
            return cls.gather_data(super())
    
    class B(A):
        _data = "B data"
        @classmethod
        def data(cls):
            return cls.gather_data(super())