如何在Python中使用字符串值创建可索引和可切片的枚举?
我有一个这样的文件:如何在Python中使用字符串值创建可索引和可切片的枚举?,python,python-3.x,Python,Python 3.x,我有一个这样的文件: class Level(Enum): prerequisite_level: Optional["Level"] dependent_level: Optional["Level"] lower_priority_levels: List["Level"] greater_priority_levels: List["Level"] DATA_CHECK = "data check" DESIGN_CHECK = "desi
class Level(Enum):
prerequisite_level: Optional["Level"]
dependent_level: Optional["Level"]
lower_priority_levels: List["Level"]
greater_priority_levels: List["Level"]
DATA_CHECK = "data check"
DESIGN_CHECK = "design check"
ALERT = "alert"
枚举值是按特定顺序排列的,基于这些级别,我需要能够获得上一个、下一个以及所有上一个和下一个级别。我相信我需要能够以数字形式索引这些级别以获得这些值,因此我添加了一个常量以实现这一点:
INCREASING_PRIORITY_LEVELS: List[Level] = list(Level)
for priority_level_index, threshold_level in enumerate(Level):
if priority_level_index > 0:
threshold_level.prerequisite_level = Level[priority_level_index - 1]
else:
threshold_level.prerequisite_level = None
if priority_level_index < len(Level) - 1:
threshold_level.dependent_level = Level[priority_level_index + 1]
else:
threshold_level.dependent_level = None
threshold_level.lower_priority_levels = Level[:priority_level_index]
threshold_level.greater_priority_levels = Level[priority_level_index + 1:]
增加优先级级别:列表[级别]=列表(级别)
对于优先级级别索引,枚举中的阈值级别(级别):
如果优先级级别索引>0:
阈值\级别。先决条件\级别=级别[优先级\级别\索引-1]
其他:
阈值\级别。先决条件\级别=无
如果优先级等级索引
这很笨重,我想去掉这个常数。我需要实现
\uuuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,并创建一个子类Enum
,将前面提到的子类EnumMeta
作为元类,以便可以根据需要对该新子类Enum
的任何子类进行索引:
from itertools import islice
from enum import Enum, EnumMeta
class IndexableEnumMeta(EnumMeta):
def __getitem__(cls, index):
if isinstance(index, slice):
return [cls._member_map_[i] for i in islice(cls._member_map_, index.start, index.stop, index.step)]
if isinstance(index, int):
return cls._member_map_[next(islice(cls._member_map_, index, index + 1))]
return cls._member_map_[index]
class IndexableEnum(Enum, metaclass=IndexableEnumMeta):
pass
class Level(IndexableEnum):
DATA_CHECK = "data check"
DESIGN_CHECK = "design check"
ALERT = "alert"
因此级别[1:3]
返回:
[<Level.DESIGN_CHECK: 'design check'>, <Level.ALERT: 'alert'>]
Level.DESIGN_CHECK
(值得赞扬的是@EthanFurman指出了子类化EnumMeta
的可行性)在使用方面实现相同结果的一个可能的替代方法是使用集合。取而代之的是namedtuple
:
from collections import namedtuple
LevelSequence = namedtuple('Level', ('DATA_CHECK', 'DESIGN_CHECK', 'ALERT'))
Level = LevelSequence('data check', 'design check', 'alert')
以便:
Level.DESIGN\u CHECK
和Level[1]
都返回“DESIGN CHECK”
,并且
级别[1:3]
返回(“设计检查”、“警报”)
我很难理解上面的内容:。。。[评论澄清前四个应该是属性,prequisite
和dependent
分别是前面和后面的成员]
解决方案是在初始化当前成员时修改以前的成员(诀窍是直到成员创建和初始化之后,当前成员才添加到父级Enum
)。下面是使用stdlib的Enum
1(Python 3.6及更高版本)的解决方案:
在使用中:
>>> list(Level)
[<Level.DATA_CHECK: 'data check'>, <Level.DESIGN_CHECK: 'design check'>, <Level.ALERT: 'alert'>]
>>> Level.DATA_CHECK.prerequisite
None
>>> Level.DATA_CHECK.dependent
<Level.DESIGN_CHECK: 'design check'>
>>> Level.DESIGN_CHECK.prerequisite
<Level.DATA_CHECK: 'data check'>
>>> Level.DESIGN_CHECK.dependent
<Level.ALERT: 'alert'>
>>> Level.ALERT.prerequisite
<Level.DESIGN_CHECK: 'design check'>
>>> Level.ALERT.dependent
None
然后你会看到:
>>> Level.DESIGN_CHECK
<Level.DESIGN_CHECK>
>Level.DESIGN\u检查
1如果使用Python 3.5或更早版本,则需要使用2
2披露:我是、和库的作者。是的,因为它覆盖了生成Enum
类实例的元类的\uuuu getitem\uuuuuuuu
。我用一个解决方案更新了我的答案,只覆盖了一个特定类的\uu getitem\uuuuuu
。非常棒的工作。我个人不会用我的工作环境来换取这么多的复杂性,但是其他人可能会这样做。如果目标是使面向用户的子类级别尽可能干净,那么创建修改副本EnumMeta
和Enum
类的复杂性可以隐藏到单独的模块中。正如您从上述示例中注意到的,使用子类EnumMeta
创建新的Enum
与类MyEnum(Enum,metaclass=MyNewMetaclass)一样简单。
级别值在ORM中用作字段值,并从API返回,因此它们不应该是整数。当存在(具有)数据检查级别时,您只能创建(具有)设计检查级别的(实例),因此level.design\u check.prerequisite==level.data\u check和level.data\u check.dependent==level.design\u check
@l0b0:Ah,好的。更新了我的答案以更好地匹配您的问题。@l0b0:Woops--将,name
添加到\uuuu init\uuuuuu
中@l0b0:做了一点修改--更新了\u generate\u next\u value\uuuuu
并删除了\uuu new\uuuuu
方法。这可能要求太多了,但是为什么\u生成下一个值\u
没有self
作为第一个参数?这打破了第8页的空白:“方法的N805第一个参数应命名为‘self’”。而且,mypy
似乎认为自己是self.\uuuuu class\uuuuu.\uu成员\uu map\uuuu
具有类型级别
。
>>> list(Level)
[<Level.DATA_CHECK: 'data check'>, <Level.DESIGN_CHECK: 'design check'>, <Level.ALERT: 'alert'>]
>>> Level.DATA_CHECK.prerequisite
None
>>> Level.DATA_CHECK.dependent
<Level.DESIGN_CHECK: 'design check'>
>>> Level.DESIGN_CHECK.prerequisite
<Level.DATA_CHECK: 'data check'>
>>> Level.DESIGN_CHECK.dependent
<Level.ALERT: 'alert'>
>>> Level.ALERT.prerequisite
<Level.DESIGN_CHECK: 'design check'>
>>> Level.ALERT.dependent
None
def __repr__(self):
return '<%s.%s>' % (self.__class__.__name__, self.name)
>>> Level.DESIGN_CHECK
<Level.DESIGN_CHECK>