【问题标题】:How to check if string exists in Enum of strings?如何检查字符串枚举中是否存在字符串?
【发布时间】:2020-11-29 19:05:48
【问题描述】:

我创建了以下枚举:

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:
    ...

我现在希望能够检查一个字符串是否在这个 Enum 中,例如:

if "new_customer" in Action:
    ....

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

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'

【问题讨论】:

  • 不,我已经证明我可以做类似"new_customer" in [i for i in Action] 的事情,但我想要更干净的事情,比如"new_customer" in Action
  • 我重新打开了这个问题。它是关于字符串的,并且不限制 try/catch

标签: python class oop enums overriding


【解决方案1】:

我今天刚碰到这个问题;我不得不为 Python 3.8 更改一些子包。

以下可能是其他解决方案的替代方案,其灵感来自here 对类似问题的出色回答,以及@MadPhysicist 的answer on this page

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

【讨论】:

  • 非常干净的解决方案,通过使用 in 关键字可以达到我想要的效果。谢谢!
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    给定语言的枚举

    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
    

    【讨论】:

      【解决方案4】:

      由于 Action 是 Enum 的派生类,我们可以利用 Enum 有一个名为 _value2member_map_ 的成员这一事实。

      value2member_map 是一个私有属性(即在 CPython 内部)将值映射到名称(但仅适用于可散列值)。但是,依赖私有属性并不是一个好主意,因为它们可以随时更改。

      Reference

      我们得到以下信息:

      if "new_customer" in Action._value2member_map_:  # works
      

      接近你想要的:

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

      【讨论】:

        【解决方案5】:

        您还可以通过括号检查枚举中的包含,例如在 dict 中

        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")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-28
          • 2012-06-03
          • 2014-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多