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?