You can create a AbstractDataclass class which guarantees this behaviour, and you can use this every time you have a situation like the one you described.
@dataclass
class AbstractDataclass(ABC):
def __new__(cls, *args, **kwargs):
if cls == AbstractDataclass or cls.__bases__[0] == AbstractDataclass:
raise TypeError("Cannot instantiate abstract class.")
return super().__new__(cls)
So, if Identifier inherits from AbstractDataclass instead of from ABC directly, modifying the __post_init__ will not be needed.
@dataclass
class Identifier(AbstractDataclass):
sub_tokens: List[str]
@staticmethod
def from_sub_tokens(sub_tokens):
return SimpleIdentifier(sub_tokens) if len(sub_tokens) == 1 else CompoundIdentifier(sub_tokens)
@dataclass
class SimpleIdentifier(Identifier):
pass
@dataclass
class CompoundIdentifier(Identifier):
pass
Instantiating Identifier will raise TypeError but not instantiating SimpleIdentifier or CompountIdentifier.
And the AbstractDataclass can be re-used in other parts of the code.
Videos
You can create a AbstractDataclass class which guarantees this behaviour, and you can use this every time you have a situation like the one you described.
@dataclass
class AbstractDataclass(ABC):
def __new__(cls, *args, **kwargs):
if cls == AbstractDataclass or cls.__bases__[0] == AbstractDataclass:
raise TypeError("Cannot instantiate abstract class.")
return super().__new__(cls)
So, if Identifier inherits from AbstractDataclass instead of from ABC directly, modifying the __post_init__ will not be needed.
@dataclass
class Identifier(AbstractDataclass):
sub_tokens: List[str]
@staticmethod
def from_sub_tokens(sub_tokens):
return SimpleIdentifier(sub_tokens) if len(sub_tokens) == 1 else CompoundIdentifier(sub_tokens)
@dataclass
class SimpleIdentifier(Identifier):
pass
@dataclass
class CompoundIdentifier(Identifier):
pass
Instantiating Identifier will raise TypeError but not instantiating SimpleIdentifier or CompountIdentifier.
And the AbstractDataclass can be re-used in other parts of the code.
The easiest way I have found is to check the type of the object in the __post_init__ method:
@dataclass
class Identifier(ABC):
...
def __post_init__(self):
if self.__class__ == Identifier:
raise TypeError("Cannot instantiate abstract class.")
...