Even if a class is inherited from ABC
, it can still be instantiated unless it contains abstract methods.
Having the code below, what is the best way to prevent an Identifier
object from being created: Identifier(['get', 'Name'])
?
JavaScript
x
22
22
1
from abc import ABC
2
from typing import List
3
from dataclasses import dataclass
4
5
@dataclass
6
class Identifier(ABC):
7
sub_tokens: List[str]
8
9
@staticmethod
10
def from_sub_tokens(sub_tokens):
11
return SimpleIdentifier(sub_tokens) if len(sub_tokens) == 1 else CompoundIdentifier(sub_tokens)
12
13
14
@dataclass
15
class SimpleIdentifier(Identifier):
16
pass
17
18
19
@dataclass
20
class CompoundIdentifier(Identifier):
21
pass
22
Advertisement
Answer
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.
JavaScript
1
7
1
@dataclass
2
class AbstractDataclass(ABC):
3
def __new__(cls, *args, **kwargs):
4
if cls == AbstractDataclass or cls.__bases__[0] == AbstractDataclass:
5
raise TypeError("Cannot instantiate abstract class.")
6
return super().__new__(cls)
7
So, if Identifier
inherits from AbstractDataclass
instead of from ABC
directly, modifying the __post_init__
will not be needed.
JavaScript
1
18
18
1
@dataclass
2
class Identifier(AbstractDataclass):
3
sub_tokens: List[str]
4
5
@staticmethod
6
def from_sub_tokens(sub_tokens):
7
return SimpleIdentifier(sub_tokens) if len(sub_tokens) == 1 else CompoundIdentifier(sub_tokens)
8
9
10
@dataclass
11
class SimpleIdentifier(Identifier):
12
pass
13
14
15
@dataclass
16
class CompoundIdentifier(Identifier):
17
pass
18
Instantiating Identifier
will raise TypeError
but not instantiating SimpleIdentifier
or CompountIdentifier
.
And the AbstractDataclass
can be re-used in other parts of the code.