Search code examples
pythoninheritancepython-dataclasses

Can a dataclass inherit attributes from a normal Python class?


I have a legacy class which was used as a data structure. It holds some attributes and some methods (like from_dict() and to_dict() used in the past). That class also inherits some attributes from a another normal base class.

I wish to move all these attributes to a new @dataclass . Can my new dataclass inherit all these old attributes from the existing plain class? But obviously not the methods.

I would like to achieve something similar to this:

from dataclasses import dataclass


class BaseClass1:
    def __init__(
        self,
        id: int,
        type: str,
    ):
        self.id = id
        self.type = type

    def to_dict(self):
        # Dummy code here
        pass

    def from_dict(self):
        # Dummy code here
        pass


class BaseClass2(BaseClass1):
    def __init__(self, speed: float, **kwargs):
        self.speed = speed

        super().__init__(**kwargs)

    def to_dict(self):
        # Dummy code here
        pass

    def from_dict(self):
        # Dummy code here
        pass


@dataclass
class NewDataStructure(BaseClass2):
    color: str
    owner: str


if __name__ == "__main__":
    new_data = NewDataStructure(
        color="red", owner="john", speed=23.7, id=345, type="car"
    )

    print(new_data)

Solution

  • I would use multiple inheritance here with the final class inheriting from both a dataclass and the normal base class. That way you can just forward initialization to bases __init__ methods and any further change will be automatically included.

    From your example, I would use:

    @dataclass
    class TmpDataStructure():
        color: str
        owner: str
    
    class NewDataStructure(TmpDataStructure, BaseClass2):
        def __init__(self, **kwargs):
            super().__init__(**{k: v for k, v in kwargs.items()
                                if k in TmpDataStructure.__match_args__})
            BaseClass2.__init__(self, **{k: v for k, v in kwargs.items()
                                         if k not in TmpDataStructure.__match_args__})
    

    You will be able to safely do:

    new_data = NewDataStructure(
        color="red", owner="john", speed=23.7, id=345, type="car"
    )
    
    print(new_data)
    

    But you would only get the fields defined in the dataclass:

    NewDataStructure(color='red', owner='john')
    

    And this will also inherit the methods from BaseClass2 and BaseClass1...