如何检查字符串枚举中是否存在字符串?

How to check if string exists in Enum of strings?

我创建了以下枚举:

from enum import Enum

class Action(str, Enum):
    NEW_CUSTOMER = "new_customer"
    LOGIN = "login"
    BLOCK = "block"

我也继承了 str,所以我可以做以下事情:

action = "new_customer"
...
if action == Action.NEW_CUSTOMER:
    ...

我现在希望能够检查此枚举中是否有字符串,例如:

if "new_customer" in Action:
    ....

我尝试将以下方法添加到 class:

def __contains__(self, item):
    return item in [i for i in self]

然而,当我运行这段代码时:

print("new_customer" in [i for i in Action])
print("new_customer" in Action)

我得到这个异常:

True
Traceback (most recent call last):
  File "/Users/kevinobrien/Documents/Projects/crazywall/utils.py", line 24, in <module>
    print("new_customer" in Action)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/enum.py", line 310, in __contains__
    raise TypeError(
TypeError: unsupported operand type(s) for 'in': 'str' and 'EnumMeta'

您可以通过调用它来检查枚举是否包含一个值:

>>> Action('new_customer')
Action.NEW_CUSTOMER

如果您传入的对象不能保证在枚举中,您可以使用 try 块来捕获结果 ValueError。例如,

def is_action(obj):
    try:
        Action(obj)
    except ValueError:
        return False
    return True

由于 Action 是 Enum 的派生 class,我们可以利用 Enum 有一个名为 _value2member_map_.

的成员这一事实

value2member_map is a private attribute (i.e. Internally in CPython) tthat maps values to names(will only work for hashable values though). However, it's not a good idea to rely on private attributes as they can be changed anytime.

我们得到以下信息:

if "new_customer" in Action._value2member_map_:  # works

接近您的要求:

if "new_customer" in Action:  # doesn't work (i.e. TypeError)

我今天刚遇到这个问题;我不得不为 Python 3.8.

更改一些子包

也许下面是其他解决方案的替代方案,灵感来自出色的答案 here to a similar question, as well as @MadPhysicist's :

from enum import Enum, EnumMeta


class MetaEnum(EnumMeta):
    def __contains__(cls, item):
        try:
            cls(item)
        except ValueError:
            return False
        return True    


class BaseEnum(Enum, metaclass=MetaEnum):
    pass


class Stuff(BaseEnum):
    foo = 1
    bar = 5

测试(在 py37 或 38 中):

>>> 1 in Stuff
True

>>> Stuff.foo in Stuff
True

>>> 2 in Stuff
False

>>> 2.3 in Stuff
False

>>> 'zero' in Stuff
False

给定一个语言枚举

class Language(enum.Enum):
    en = 'en'
    zh = 'zh'

    @classmethod
    def has_member_key(cls, key):
        return key in cls.__members__

print(Language.has_member_key('tu')) => False
print(Language.has_member_key('en')) => True

你也可以像在字典中一样通过括号检查枚举中的包含

class Action(Enum):
    NEW_CUSTOMER = 1
    LOGIN = 2
    BLOCK = 3

action = 'new_customer'
try:
    action = Action[action.upper()]
    print("action type exists")
except KeyError:
    print("action type doesn't exists")