我正在规范化现有的凌乱数据,我想创建一个Enum
,它允许成员的规范名称使用同义词,这样,如果有人在实例化枚举时使用同义词值,他们将获得规范名称。即
class TrainOutcome(enum.Enum):
PASSED = "PASSED"
SUCCESS = "PASSED" # Deprecated synonym for "PASSED"
FAILED = "FAILED"
STARTED = "STARTED"
这执行得很好,但结果枚举的行为不符合预期:
>>> TrainOutcome("PASSED")
<TrainOutcome.PASSED: 'PASSED'>
# I want to get <TrainOutcome.PASSED: 'PASSED'> here as well
>>> TrainOutcome("SUCCESS")
ValueError: 'SUCCESS' is not a valid TrainOutcome
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/enum.py", line 309, in __call__
return cls.__new__(cls, value)
File "/usr/lib/python3.8/enum.py", line 600, in __new__
raise exc
File "/usr/lib/python3.8/enum.py", line 584, in __new__
result = cls._missing_(value)
File "/usr/lib/python3.8/enum.py", line 613, in _missing_
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 'SUCCESS' is not a valid TrainOutcome
尽管__members__
属性似乎完全按照我所希望的方式映射事物:
>>> TrainOutcome.__members__
mappingproxy({'PASSED': <TrainOutcome.PASSED: 'PASSED'>, 'SUCCESS': <TrainOutcome.PASSED: 'PASSED'>, 'FAILED': <TrainOutcome.FAILED: 'FAILED'>, 'STARTED': <TrainOutcome.STARTED: 'STARTED'>})
>>> TrainOutcome['SUCCESS']
<TrainOutcome.PASSED: 'PASSED'>
>>> TrainOutcome['PASSED']
<TrainOutcome.PASSED: 'PASSED'>
如何创建枚举,使构造函数接受并返回与索引类型相同的值
Edit:现有的Python Enum with duplicate values没有回答我的问题,因为本质上它试图实现与我所追求的相反的目标。OP想要使结果值更清晰,我想要使它们不那么清晰。事实上,理想的解决方案是根本不使用同义词成员(因为我在SQLAlchemy上下文中使用生成的Enum
,它查看的是成员名称,而不是它们的值),而只是在构造期间用"PASSED"
悄悄地替换"SUCCESS"
,但在调用super()
的枚举上定义一个自定义的__init__
似乎不起作用
Edit:This question and answer提供了迄今为止最简单的解决方案:使用aenum.MultiValueEnum
另外,这里有一个自主开发的解决方案,它似乎符合您在Python 3.6+中应该做的事情的精神,某种程度上受到了@Green-clope-Guy答案的启发:
class EnumSynonymMixin:
"""
Enum mixin which provides the ability to define synonyms,
ie. values which can be passed into an enum's constructor, that
name the same member as one of the defined values, without adding
any extra members (useful for using with SQLAlchemy's Enum mapping)
For example:
class MyEnum(EnumSynonymMixin, enum.Enum):
FOO = "FOO"
BAR = "BAR"
@classmethod
def synonyms(cls):
return {"MYFOO": "FOO"}
>>> MyEnum("MYFOO")
<MyEnum.FOO: 'FOO'>
"""
@classmethod
def synonyms(cls):
"""Override to provide a dictionary of synonyms for values that can be
passed to the constructor"""
return {}
@classmethod
def _missing_(cls, val):
synonyms = cls.synonyms()
if val in synonyms:
return cls.__members__[synonyms[val]]
return super()._missing(val)
class TrainOutcome(EnumSynonymMixin, enum.Enum):
PASSED = "PASSED"
FAILED = "FAILED"
STARTED = "STARTED"
@classmethod
def synonyms(cls):
return {"SUCCESS": "PASSED"}
这应该是你想要的。本质上,类包装器使
TrainOutcome(value)
的行为类似于TrainOutcome[value]
,否则前者会产生错误(如您所描述的情况,您试图用“SUCCESS”调用它)。它通过截取对__new__()
的调用并替换第一个参数来实现这一点根据对你问题的评论,你可能不应该这样做——我想不出为什么
TrainOutcome['SUCCESS']
不能满足你的需要相关问题 更多 >
编程相关推荐