如何测试具有特定名称的Enum成员是否存在?

时间:2015-04-22 11:02:25

标签: python python-3.x enums

使用Python 3.4我想测试Enum类是否包含具有特定名称的成员。

示例:

class Constants(Enum):
    One = 1
    Two = 2
    Three = 3

print(Constants['One'])
print(Constants['Four'])

给出:

Constants.One
  File "C:\Python34\lib\enum.py", line 258, in __getitem__
    return cls._member_map_[name]
KeyError: 'Four'

我可以抓住KeyError并将异常作为存在的指示,但也许有更优雅的方式?

5 个答案:

答案 0 :(得分:32)

您可以使用Enum.__members__ - an ordered dictionary mapping names to members

In [12]: 'One' in Constants.__members__
Out[12]: True

In [13]: 'Four' in Constants.__members__
Out[13]: False

答案 1 :(得分:16)

我会说这属于EAFP(更容易要求宽恕而非许可),这是一个相对独特的Python概念。

  

比获得许可更容易请求宽恕。这种常见的Python编码风格假设存在有效的键或属性,并且如果假设被证明是错误则捕获异常。这种干净和快速的风格的特点是存在许多try和except语句。该技术与许多其他语言(如C。

)共有的LBYL风格形成对比

这与LBYL(跳跃前看)相反,当你说你正在寻找更优雅的方式时,这就是我想你想要的。"

  

在你跳跃之前先看看。这种编码风格在进行调用或查找之前明确地测试前置条件。这种风格与EAFP方法形成对比,其特点是存在许多if语句。

     

在多线程环境中,LBYL方法可能会冒险在“外观”和“跳跃”之间引入竞争条件。例如,代码,如果映射中的键:如果另一个线程在测试之后但在查找之前从映射中删除了键,则返回映射[key]可能会失败。这个问题可以通过锁定或使用EAFP方法来解决。

因此,根据文档,实际上最好使用try / except块来解决您的问题。

TL; DR

使用try / except块来捕获KeyError例外。

答案 2 :(得分:4)

可以使用以下内容测试名称是否存在:

if any(x for x in Constants if x.name == "One"):
  # Exists
else:
  # Doesn't Exist

使用x.value测试枚举值:

if any(x for x in Constants if x.value == 1):
  # Exists
else:
  # Doesn't Exist

答案 3 :(得分:3)

为了提高可读性,您可以将以上建议作为类方法。 例如:

class Constants(Enum):
    One = 1
    Two = 2
    Three = 3

    @classmethod
    def has_key(cls, name):
        return name in cls.__members__ # solution above 1
        # return any(x for x in cls if x.name == name) # or solution above 2

要使用:

In [6]: Constants.has_key('One')
Out[6]: True

In [7]: Constants.has_key('Four')
Out[7]: False

答案 4 :(得分:0)

有点明显,所以不确定为什么没有提到它,可能有一些我没有想到的陷阱,但 hasattr 可以以编程方式迭代它们并检查成员资格:

class DataSource(Enum):
    ENCYCLOPEDIA = "encyclopedia"
    NEWSPAPER = "newspaper"
    BOOK = "book"
    MAGAZINE = "magazine"

input_sources = [
        {"dataSource": "encyclopedia"},
        {"dataSource": "wikipedia"},
        {"dataSource": None}
        ]

data_sources = [set(
        datum['dataSource']
        for datum in input_sources
        if datum['dataSource'] is not None
            and hasattr(DataSource, datum.get('dataSource', '').upper())
        )]

输出为:

[  ]:  data_sources
[51]:  [{'encyclopedia'}]