使用Python Enum类,是否有一种方法可以在不使用try / catch的情况下测试Enum是否包含特定的int值?
使用以下课程:
from enum import Enum
class Fruit(Enum):
Apple = 4
Orange = 5
Pear = 6
如何测试值6(返回true)或值7(返回false)?
使用Python Enum类,是否有一种方法可以在不使用try / catch的情况下测试Enum是否包含特定的int值?
使用以下课程:
from enum import Enum
class Fruit(Enum):
Apple = 4
Orange = 5
Pear = 6
如何测试值6(返回true)或值7(返回false)?
Answers:
请注意,有个Enum
具有的成员_value2member_map_
(未记录,可能在将来的python版本中更改/删除):
print(Fruit._value2member_map_)
# {4: <Fruit.Apple: 4>, 5: <Fruit.Orange: 5>, 6: <Fruit.Pear: 6>}
您可以Enum
根据此地图测试您的值是否在其中:
5 in Fruit._value2member_map_ # True
7 in Fruit._value2member_map_ # False
如果您不想依赖此功能,则可以选择以下方法:
values = [item.value for item in Fruit] # [4, 5, 6]
或(可能更好):使用set
; 该in
运营商将更加有效:
values = set(item.value for item in Fruit) # {4, 5, 6}
然后用
5 in values # True
7 in values # False
has_value
到您的课程然后可以将其作为方法添加到您的类中:
class Fruit(Enum):
Apple = 4
Orange = 5
Pear = 6
@classmethod
def has_value(cls, value):
return value in cls._value2member_map_
print(Fruit.has_value(5)) # True
print(Fruit.has_value(7)) # False
如果您想测试名称(而不是值),我将使用_member_names_
:
'Apple' in Fruit._member_names_ # True
'Mango' in Fruit._member_names_ # False
HTTPStatus
标准库中的枚举,该枚举目前包含57个条目。我永远不会处理枚举中的全部值列表,因此我想避免缓存它们。
set
为查找创建一个。这将使用一些额外的内存,但不会占用大量内存...
return any(value == item.value[0] for item in cls)
与Python3一起使用时Enum结构是否发生了变化?
您可以使用Enum.__members__
-将名称映射到成员的有序字典:
In [12]: 'Apple' in Fruit.__members__
Out[12]: True
In [13]: 'Grape' in Fruit.__members__
Out[13]: False
在Reda Maachi开始的基础上:
6 in Fruit.__members__.values()
返回True
7 in Fruit.__members__.values()
返回False
>>> Fruit.Orange in Fruit.__members__.values() True
有一种方法可以使所有枚举都可以检查是否存在某个项目:
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"
现在,您可以轻松进行检查:
>>> "foo" in MyEnum
True
如果所有枚举的值始终是同一类型,甚至可以简化,例如字符串:
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"
编辑:另一个版本,技术上是最正确的版本:
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"
只是检查它是否在 Enum. _value2member_map_
In[15]: Fruit._value2member_map_
Out[15]: {4: <Fruit.Apple: 4>, 5: <Fruit.Orange: 5>, 6: <Fruit.Pear: 6>}
In[16]: 6 in Fruit._value2member_map_
Out[16]: True
In[17]: 7 in Fruit._value2member_map_
Out[17]: False
_value2member_map_
是未记录的功能,因此最好避免使用它。
您可以使用__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()]
还有一个没人提到的班轮解决方案:
is_value_in_fruit = any(f.value == value_to_check for f in Fruit)
另外,如果您使用IntEnum
而不是Enum
((class Fruit(IntEnum)
),则可以执行此操作
is_value_in_fruit = any(f == value_to_check for f in Fruit)
答案的EAFP版本:
try:
Fruit(val)
return True
except ValueError:
return False
别。
如果您使用的是Enum,则可以使用
if isinstance(key, Fruit):
但是,否则,尝试..是测试枚举的Python方法。确实,对于鸭式范例的任何突破。
在IntEnum中测试int的正确方法是pythonic,是允许它执行并在失败时捕获ValueError。
上面建议的许多解决方案均已被3.8弃用(“ DeprecationWarning:在包含检查中使用非枚举会在Python 3.8中引发TypeError”)
如果您真的对保持代码现代化不感兴趣,那么您可以使用
if key in Fruit:
IntEnum
+ __members__
您可以使用IntEnum
并__members__
实现所需的行为:
from enum import IntEnum
class Fruit(IntEnum):
Apple = 4
Orange = 5
Pear = 6
>>> 6 in Fruit.__members__.values()
True
>>> 7 in Fruit.__members__.values()
False
Enum
+清单理解+ .value
如果您必须/想要坚持Enum
,可以执行以下操作:
>>> 6 in [f.value for f in Fruit]
True
>>> 7 in [f.value for f in Fruit]
False
EAPF + ValueError
或者,您可以使用比许可方法更容易请求宽恕的方法:
try:
Fruit(x)
except ValueError:
return False
else:
return True