Python factory classmethod inheritence

38 views Asked by At

Sometimes it is better to use factory classmethod to create an instance,like:

class Configuration:
    def __init__(self, attr1: int, attr2: int) -> None:
        self._attr1 = attr1
        self._attr2 = attr2

    @property
    def attr1(self) -> int:
        return self._attr1

    @property
    def attr2(self) -> int:
        return self._attr2
        
    @classmethod
    def from_file(cls, filepath: str) -> Configuration:
        parsed_data = cls._parse_config_file(filepath)
        computed_data = cls._precompute_stuff(parsed_data)
        return cls(
            attr1=parsed_data,
            attr2=computed_data,
        )

    @classmethod
    def _parse_config_file(cls, filepath: str) -> int:
        # parse the file in filepath and return the data    
        ...

    @classmethod
    def _precompute_stuff(cls, data: int) -> int:
        # use data parsed from a config file to calculate new data
        ...

I want to inherit this class to add more data member ,to do this, I want to override from_file method like below:

class DerivedConfiguration(Configuration):
    def __init__(self, attr1: int, attr2: int, attr3: int) -> None:
        self._attr1 = attr1
        self._attr2 = attr2
        self._attr3 = attr3
    @property
    def attr3(self) -> int:
        return self._attr3

        
    @classmethod
    def from_file(cls, filepath: str) -> Configuration:
        base_config = super().from_file(filepath)
        attr3 = ... # do something with attr3
        return cls(attr1=base_config._attr1,attr2=base_config._attr2,attr3=attr3)

if I do this, it will raise TypeError,since the derived class will pass its cls to base class, lead the return statement of from_file method raise TypeError.

to solve this problem, I put parse logic in another class method parse_config and let it return all data member, and let derived class to override this method rather than parse_config itself

class Configuration:
    def __init__(self, attr1: int, attr2: int) -> None:
        self._attr1 = attr1
        self._attr2 = attr2

    @property
    def attr1(self) -> int:
        return self._attr1

    @property
    def attr2(self) -> int:
        return self._attr2
        
    @classmethod
    def from_file(cls, filepath: str) -> Configuration:
        configs = cls.parse_config(filepath)
        return cls(*configs)

    @classmethod
    def parse_config(cls,filepath:str):
        parsed_data = cls._parse_config_file(filepath)
        computed_data = cls._precompute_stuff(parsed_data)
        return parsed_data,computed_data 
 
    @classmethod
    def _parse_config_file(cls, filepath: str) -> int:
        # parse the file in filepath and return the data    
        ...

    @classmethod
    def _precompute_stuff(cls, data: int) -> int:
        # use data parsed from a config file to calculate new data
        ...


class DerivedConfiguration(Configuration):
    def __init__(self, attr1: int, attr2: int, attr3: int) -> None:
        self._attr1 = attr1
        self._attr2 = attr2
        self._attr3 = attr3
    @property
    def attr3(self) -> int:
        return self._attr3

        
    @classmethod
    def from_file(cls, filepath: str) -> Configuration:
        configs = cls.parse_config(filepath)
        return cls(*configs)

    @classmethod
    def parse_config(cls,filepath:str):
        base_configs = super().parse_config(filepath)
        attr3 = ... # do something with attr3
        return *base_configs,attr3

but I think it is a little bit strange, is there more standard or elegant way to solve thid problem?

0

There are 0 answers