如何在不使用try/catch的情况下测试Python Enum中是否存在int值?

Nat*_*ner 43 python enums

使用Python Enum类,有没有办法测试Enum是否包含特定的int值而不使用try/catch?

使用以下课程:

from enum import Enum

class Fruit(Enum):
    Apple = 4
    Orange = 5
    Pear = 6
Run Code Online (Sandbox Code Playgroud)

如何测试值6(返回true)或值7(返回false)?

hir*_*ist 73

你可以列出这样的值:

print(Fruit._value2member_map_)
# {4: <Fruit.Apple: 4>, 5: <Fruit.Orange: 5>, 6: <Fruit.Pear: 6>}
Run Code Online (Sandbox Code Playgroud)

或者(可能更好):使用Enum; 该_value2member_map_运营商将更加有效:

5 in Fruit._value2member_map_  # True
7 in Fruit._value2member_map_  # False
Run Code Online (Sandbox Code Playgroud)

然后测试

values = [item.value for item in Fruit]  # [4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

您也可以将此作为方法添加到您的班级:

values = set(item.value for item in Fruit)  # {4, 5, 6}
Run Code Online (Sandbox Code Playgroud)

如果你想测试名字(而不是价值),Reda Maachi的答案涵盖了我会做什么.

  • 我个人更喜欢第二种解决方案。谢谢。 (3认同)
  • 任何一个建议都不是特别节省内存或时间,尽管在这些方面也不是很重要。就我而言,我正在使用标准库中的 `HTTPStatus` 枚举,它现在包含 57 个条目。我永远不会处理枚举中的整个值列表,缓存它们是我想避免的事情。 (2认同)
  • @none 如果您担心速度,您可以为查找创建一个“集合”。这会使用一些额外的内存,但数量不会很大...... (2认同)

Ber*_*pac 19

有一种方法可以让所有枚举都能够检查项目是否存在:

import enum 

class MyEnumMeta(enum.EnumMeta): 
    def __contains__(cls, item): 
        return item in [v.value for v in cls.__members__.values()] 

class MyEnum(enum.Enum, metaclass=MyEnumMeta): 
   FOO = "foo" 
   BAR = "bar"
Run Code Online (Sandbox Code Playgroud)

现在你可以做一个简单的检查:

>>> "foo" in MyEnum
True
Run Code Online (Sandbox Code Playgroud)

如果所有枚举的值总是相同的类型,它甚至可以变得更简单——例如字符串:

import enum 
 
class MyEnumMeta(enum.EnumMeta):  
    def __contains__(cls, item): 
        return item in cls.__members__.values()

class MyEnum(str, enum.Enum, metaclass=MyEnumMeta): 
    FOO = "foo" 
    BAR = "bar"
Run Code Online (Sandbox Code Playgroud)

编辑:又一个版本,技术上最正确的一个:

import enum 

class MyEnumMeta(enum.EnumMeta): 
    def __contains__(cls, item): 
        try:
            cls(item)
        except ValueError:
            return False
        else:
            return True

class MyEnum(enum.Enum, metaclass=MyEnumMeta): 
   FOO = "foo" 
   BAR = "bar"
Run Code Online (Sandbox Code Playgroud)


Fin*_*sse 19

如果枚举有许多成员,这种方法可能会更快,因为它不会创建新列表,并且在找到给定值时停止遍历枚举:

any(x.value == 5 for x in Fruit)  # True
any(x.value == 7 for x in Fruit)  # False
Run Code Online (Sandbox Code Playgroud)


Red*_*chi 16

您可以使用Enum.__members__- 将名称映射到成员的有序字典:

In [12]: 'Apple' in Fruit.__members__
Out[12]: True

In [13]: 'Grape' in Fruit.__members__
Out[13]: False
Run Code Online (Sandbox Code Playgroud)

  • Enum中没有包含值的成员吗?这不奇怪吗? (5认同)
  • 问题是要求测试一个int值,而不是字符串. (3认同)
  • 这与问题提出的方向相反。 (3认同)

Ray*_*emi 13

我只是将 IntEnum 转换为列表并正常测试它:

from enum import IntEnum
class Foo(IntEnum):
    ONE = 1
    TWO = 2
    THREE = 3

print(1 in list(Foo))
True
print(4 in list(Foo))
False
Run Code Online (Sandbox Code Playgroud)

  • 也许这只适用于“IntEnum”。我需要执行以下操作来获取成员值作为列表 `[m.value for m in MyEnum.__members__.values()]` (4认同)

man*_*u3d 7

建立在 Reda Maachi 开始的基础上:

6 in Fruit.__members__.values() 
Run Code Online (Sandbox Code Playgroud)

返回真

7 in Fruit.__members__.values()  
Run Code Online (Sandbox Code Playgroud)

返回假

  • 我想指出的是,这仅适用于 IntEnum。 (6认同)
  • 这看起来是一种非常干净的方式。不幸的是,当我测试这个(至少在 Py3.7 中)时,它并没有那样工作。Fruit.__members__.values() 的计算结果为 odict_values([&lt;Fruit.Apple: 4&gt;, &lt;Fruit.Orange: 5&gt;, &lt;Fruit.Pear: 6&gt;]),并且上述 6 和 7 的测试均返回 False我。但这会返回 true: ```&gt;&gt;&gt; Fruit.Orange in Fruit.__members__.values() True``` (2认同)

Kon*_*hog 7

本来,不要。

\n

如果您使用 Enum,则可以使用以下命令测试枚举

\n
     if isinstance(key, Fruit):\n
Run Code Online (Sandbox Code Playgroud)\n

但除此之外, try.. 是测试枚举的 Python 方式。事实上,对于鸭子类型范式的任何突破。

\n

测试 IntEnum 中 int 的正确且 Python 的方法是尝试一下,如果失败则捕获 ValueError。

\n

上面提出的许多解决方案已被积极弃用,并将在 3.8 中被禁止(“DeprecationWarning:在包含检查中使用非枚举将在 Python 3.8 中引发 TypeError”)

\n

从 Python 3.8 \xe2\x80\x93 将其强制转换为列表。

\n

在 3.8 左右之后,您可以通过将枚举强制转换为列表来进行测试,如下所示(使用 IntEnum)

\n
from enum import IntEnum\nclass Fruit(IntEnum):\n     Kiwi = 2\n     Apple = 4\n     Orange = 5\n     Pear = 6\n\nfor x in range(8):\n     print(f\'{x}, {x in list(Fruit)}\')\n\n
Run Code Online (Sandbox Code Playgroud)\n

将打印如下

\n
     if isinstance(key, Fruit):\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这个解决方案实际上是错误的。由于 OP 询问如何检查某个值是否在枚举中,例如 6 或 7。这将始终返回 false,因为枚举的任何成员实际上都不等于 6 或 7。尝试一下。 (4认同)
  • 但这确实做到了大多数人谷歌搜索的目的,如何检查一个值是否是一个枚举,赞成!谢谢你! (2认同)
  • 本答案中提到的 DeprecationWarning 从 Python 3.12 开始将过时。Python 3.11 现在包含通知 3.12 中即将发生的更改的信息。“DeprecationWarning:在 3.12 中 __contains__ 将不再引发 TypeError,但将返回 True 或 False,具体取决于该值是成员还是成员的值”。 (2认同)

Com*_*tMe 7

EAFP版本的答案:

try: 
    Fruit(val)
    return True
except ValueError:
    return False
Run Code Online (Sandbox Code Playgroud)


Ale*_*lig 6

您可以使用__members__特殊属性来迭代成员:

from enum import Enum

class Fruit(Enum):
    Apple = 4
    Orange = 5
    Pear = 6

    @staticmethod
    def has_value(item):
        return item in [v.value for v in Fruit.__members__.values()]
Run Code Online (Sandbox Code Playgroud)