Python 中没有抽象方法的抽象数据类:禁止实例化
Abstract dataclass without abstract methods in Python: prohibit instantiation
即使 class 继承自 ABC
,看起来它仍然可以实例化,除非它包含抽象方法。
有了下面的代码,防止创建 Identifier
对象的最佳方法是什么:Identifier(['get', 'Name'])
?
from abc import ABC
from typing import List
from dataclasses import dataclass
@dataclass
class Identifier(ABC):
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
如果这个问题已经得到回答,我提前道歉。看起来很基本,但是由于某种原因我找不到答案。
干杯,Hlib。
我找到的最简单的方法是检查 __post_init__
方法中对象的类型:
@dataclass
class Identifier(ABC):
...
def __post_init__(self):
if self.__class__ == Identifier:
raise TypeError("Cannot instantiate abstract class.")
...
您可以创建一个 AbstractDataclass
class 来保证这种行为,并且您可以在每次遇到您所描述的情况时使用它。
@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)
因此,如果 Identifier
继承自 AbstractDataclass
而不是直接继承自 ABC
,则不需要修改 __post_init__
。
@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
实例化 Identifier
将引发 TypeError
但不会实例化 SimpleIdentifier
或 CompountIdentifier
。
AbstractDataclass
可以在代码的其他部分重复使用。
即使 class 继承自 ABC
,看起来它仍然可以实例化,除非它包含抽象方法。
有了下面的代码,防止创建 Identifier
对象的最佳方法是什么:Identifier(['get', 'Name'])
?
from abc import ABC
from typing import List
from dataclasses import dataclass
@dataclass
class Identifier(ABC):
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
如果这个问题已经得到回答,我提前道歉。看起来很基本,但是由于某种原因我找不到答案。
干杯,Hlib。
我找到的最简单的方法是检查 __post_init__
方法中对象的类型:
@dataclass
class Identifier(ABC):
...
def __post_init__(self):
if self.__class__ == Identifier:
raise TypeError("Cannot instantiate abstract class.")
...
您可以创建一个 AbstractDataclass
class 来保证这种行为,并且您可以在每次遇到您所描述的情况时使用它。
@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)
因此,如果 Identifier
继承自 AbstractDataclass
而不是直接继承自 ABC
,则不需要修改 __post_init__
。
@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
实例化 Identifier
将引发 TypeError
但不会实例化 SimpleIdentifier
或 CompountIdentifier
。
AbstractDataclass
可以在代码的其他部分重复使用。