Tza*_*i T 12 python enums python-3.6
我正在尝试Flag使用抽象方法创建一个抽象枚举(实际上)。我的最终目标是能够根据我定义的基本枚举创建复合枚举的字符串表示形式。我可以在不使类抽象的情况下获得此功能。
这是基本Flag类和示例实现:
from enum import auto, Flag
class TranslateableFlag(Flag):
@classmethod
def base(cls):
pass
def translate(self):
base = self.base()
if self in base:
return base[self]
else:
ret = []
for basic in base:
if basic in self:
ret.append(base[basic])
return " | ".join(ret)
class Students(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
@classmethod
def base(cls):
return {Students.ALICE: "Alice", Students.BOB: "Bob",
Students.CHARLIE: "Charlie"}
Run Code Online (Sandbox Code Playgroud)
一个示例用法是:
((Students.ALICE | Students.BOB).translate())
[Out]: 'Alice | Bob'
Run Code Online (Sandbox Code Playgroud)
TranslateableFlag(Flag, ABC)由于MetaClass冲突,切换到失败。(我不理解这篇文章- 使用ABCMeta和EnumMeta的抽象枚举类,因此我不确定它是否在回答我的问题)。
我想以某种方式获得这样的功能:
@abstractclassmethod
@classmethod
def base(cls):
pass
Run Code Online (Sandbox Code Playgroud)
有可能实现这一目标吗?
这是使用ABCMeta和EnumMeta来调整对抽象枚举类问题的接受答案的方法,以创建所需的抽象Enum类:
from abc import abstractmethod, ABC, ABCMeta
from enum import auto, Flag, EnumMeta
class ABCEnumMeta(ABCMeta, EnumMeta):
def __new__(mcls, *args, **kw):
abstract_enum_cls = super().__new__(mcls, *args, **kw)
try: # Handle existence of undefined abstract methods.
absmethods = list(abstract_enum_cls.__abstractmethods__)
absmethods_str = ', '.join(f'{method!r}' for method in absmethods)
plural = 's' if len(absmethods) > 1 else ''
raise TypeError(
f"cannot instantiate abstract class {abstract_enum_cls.__name__!r}"
f" with abstract method{plural} {absmethods_str}")
except AttributeError:
pass
return abstract_enum_cls
class TranslateableFlag(Flag, metaclass=ABCEnumMeta):
@classmethod
@abstractmethod
def base(cls):
pass
def translate(self):
base = self.base()
if self in base:
return base[self]
else:
ret = []
for basic in base:
if basic in self:
ret.append(base[basic])
return " | ".join(ret)
class Students1(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
@classmethod
def base(cls):
return {Students1.ALICE: "Alice", Students1.BOB: "Bob",
Students1.CHARLIE: "Charlie"}
class Students2(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
# Abstract method not defined - should raise TypeError.
# @classmethod
# def base(cls):
# ...
Run Code Online (Sandbox Code Playgroud)
结果:
from abc import abstractmethod, ABC, ABCMeta
from enum import auto, Flag, EnumMeta
class ABCEnumMeta(ABCMeta, EnumMeta):
def __new__(mcls, *args, **kw):
abstract_enum_cls = super().__new__(mcls, *args, **kw)
try: # Handle existence of undefined abstract methods.
absmethods = list(abstract_enum_cls.__abstractmethods__)
absmethods_str = ', '.join(f'{method!r}' for method in absmethods)
plural = 's' if len(absmethods) > 1 else ''
raise TypeError(
f"cannot instantiate abstract class {abstract_enum_cls.__name__!r}"
f" with abstract method{plural} {absmethods_str}")
except AttributeError:
pass
return abstract_enum_cls
class TranslateableFlag(Flag, metaclass=ABCEnumMeta):
@classmethod
@abstractmethod
def base(cls):
pass
def translate(self):
base = self.base()
if self in base:
return base[self]
else:
ret = []
for basic in base:
if basic in self:
ret.append(base[basic])
return " | ".join(ret)
class Students1(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
@classmethod
def base(cls):
return {Students1.ALICE: "Alice", Students1.BOB: "Bob",
Students1.CHARLIE: "Charlie"}
class Students2(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
# Abstract method not defined - should raise TypeError.
# @classmethod
# def base(cls):
# ...
Run Code Online (Sandbox Code Playgroud)
这是 python 3.8 已接受答案的修复。唯一的变化是ABCEnumMeta. 其余部分是从原始答案复制粘贴的,以提供可运行的示例。还在 python 3.6.2 上进行了测试。
from abc import abstractmethod, ABC, ABCMeta
from enum import auto, Flag, EnumMeta
class ABCEnumMeta(EnumMeta, ABCMeta):
pass
class TranslateableFlag(Flag, metaclass=ABCEnumMeta):
@classmethod
@abstractmethod
def base(cls):
pass
def translate(self):
base = self.base()
if self in base:
return base[self]
else:
ret = []
for basic in base:
if basic in self:
ret.append(base[basic])
return " | ".join(ret)
class Students1(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
@classmethod
def base(cls):
return {Students1.ALICE: "Alice", Students1.BOB: "Bob",
Students1.CHARLIE: "Charlie"}
class Students2(TranslateableFlag):
ALICE = auto()
BOB = auto()
CHARLIE = auto()
ALL = ALICE | BOB | CHARLIE
# Abstract method not defined - should raise TypeError.
# @classmethod
# def base(cls):
# ...
Run Code Online (Sandbox Code Playgroud)