#python #abstract-class #inner-classes
#python #абстрактный класс #внутренние классы
Вопрос:
У меня есть абстрактный класс, из которого будут происходить подклассы. Конкретные реализации должны включать в себя класс Enum, который содержит набор именованных констант.
from enum import Enum
class AbstractClass:
def run(self)
print('the values are:')
for enum in ClassEnum:
print(enum.value)
self.speak()
def speak(self):
raise NotImplementedError
class ConcreteClassFirst(AbstractClass):
class ClassEnum(Enum):
RED = 0
GREEN = 1
BLUE = 2
def speak(self)
print('the colors are:')
for enum in ClassEnum:
print(enum.name)
class ConcreteClassSecond(AbstractClass):
class ClassEnum(Enum):
LION = 'scary'
ELEPHANT = 'big'
GIRAFFE = 'tall'
def speak(self)
print('the animals are:')
for enum in ClassEnum:
print(enum.name)
этот код фактически обеспечивает правильное поведение, однако я хотел бы, чтобы там была какая-то нотация (аналогичная методу NotImplementedError
on the abstract speak()
) Это указывает на то, что автор конкретного класса должен определить вызываемый внутренний Enum
класс ClassEnum
. На самом деле это необходимо для run()
метода.
Некоторые идеи должны иметь что-то вроде
class AbstractClass:
class ClassEnum(Enum):
pass
def run(self):
...
но это не вызовет ошибку, если подкласс не определяет свою собственную версию ClassEnum
. Мы могли бы попробовать
class AbstractClass:
class ClassEnum(Enum):
raise NotImplementedError
def run(self):
...
Но это предсказуемо вызывает ошибку, как только AbstractClass
определено
Я мог бы попробовать
class AbstractClass:
@property
def ClassEnum(self):
raise NotImplementedError
def run(self):
...
Но здесь неясно, что в подклассе ClassEnum на самом деле должен быть классом. Возможно, этот подход с некоторой документацией может быть уместным..
Ответ №1:
Я не думаю, что в python есть чистый способ, кроме странных метаклассов, для принудительного определения атрибутов класса в подклассах. Учитывая это, я думаю, что следующая лучшая вещь — вместо этого использовать переданные атрибуты экземпляра super.__init__()
.
from enum import Enum
class AbstractClass:
def __init__(self, behavior_enum):
"""
:param behavior_enum: enum class with values and names that determine class behavior
"""
self.behavior_enum = behavior_enum
def run(self)
print('the values are:')
for enum in self.behavior_enum:
print(enum.value)
self.speak()
def speak(self):
raise NotImplementedError
class ConcreteClassFirst(AbstractClass):
class behavior_enum(Enum):
RED = 0
GREEN = 1
BLUE = 2
def __init__(self)
super().__init__(self.behavior_enum)
def speak(self)
print('the colors are:')
for enum in self.behavior_enum:
print(enum.name)
class ConcreteClassSecond(AbstractClass):
class behavior_enum(Enum):
LION = 'scary'
ELEPHANT = 'big'
GIRAFFE = 'tall'
def __init__(self)
super().__init__(self.behavior_enum)
def speak(self)
print('the animals are:')
for enum in self.behavior_enum:
print(enum.name)