【问题标题】:How to construct a case insensitive enum?如何构造不区分大小写的枚举?
【发布时间】:2017-03-07 21:23:49
【问题描述】:

我有一个简单的 Python 2.7 枚举:

from enum import Enum

class Label(enum):
    RedApple = 1
    GreenApple = 2

我希望能够使用不区分大小写的键创建枚举对象:

fruitname = "redapple"
a = Label[fruitname]

我尝试创建一个__init__ 方法:

def __init__(self, key):
    super(Label, self).__init__()
    pass # do comparison here

但我总是遇到错误:

super(Label, self).__init__()
NameError: global name 'Label' is not defined

我想对key.lower().strip() 进行比较。这甚至可能吗?

【问题讨论】:

    标签: python python-2.7 enums


    【解决方案1】:

    在 Python 3.6 和 aenum 2.012(与 2.7 和 3.0+ 兼容)中添加了一个新方法:_missing_2 .

    在引发ValueError 之前调用此方法,以使自定义代码有机会尝试按值查找枚举成员。不幸的是,这使得它不适合您的用例 - 按名称查找。

    幸运的是,aenum 具有定义 _missing_name_ 方法的额外选项3,该方法将在名称查找失败时调用。

    上面的代码应该是这样的:

    from aenum import Enum
    
    class Label(Enum):
    
        RedApple = 1
        GreenApple = 2
    
        @classmethod
        def _missing_name_(cls, name):
            for member in cls:
                if member.name.lower() == name.lower():
                    return member
    

    并在使用中:

    >>> Label['redapple']
    <Label.RedApple: 1>
    

    如果坚持使用 3.6 标准库(或想保持兼容),您可以(ab)使用 _missing_,但是:

    • 您必须改用Label('redapple')(圆括号,而不是方括号),并且
    • 您将违背枚举的设计(“redapple”是名称,而不是值)

    1 披露:我是Python stdlib Enumenum34 backportAdvanced Enumeration (aenum) 库的作者。

    2enum34 没有这些改进,因为它仅用于修复错误。

    3_missing_value_aenum 中是首选,因为它更明确地说明了它正在检查的内容,但为了与标准库兼容,它回退到_missing_

    4 aenum v2.0.2 有一个错误,如果 _missing_name_ 未被覆盖,则为值和名称调用 _missing_ - 这在 v2.0.3+ 中已修复。

    【讨论】:

    • 很好的答案!谢谢!
    • 好的。我正在对此进行测试,发现 missing 没有被调用。
    • ValueError: redapple is not a valid Label
    • @Hephaestus:升级到 2.0.2,两种方法都可以正常工作。 :)
    • @Hephaestus:刚刚意识到我推荐了一种不好的方法——重新设计了答案。
    【解决方案2】:

    不是 100% 确定这将在 Python 2.7 中工作,但我想出了一个简单的方法来使其完全按照 Python 3.6+ 的要求工作。

    这个想法是,名称的查找是由使用方括号的类完成的,这意味着它使用元类中的__getitem__。因此,您可以创建一个简单的元类来实现不区分大小写的搜索。由于它将扩展现有的EnumMeta,它将与现有的枚举完全兼容:

    class CaseInsensitiveEnumMeta(EnumMeta):
        def __getitem__(self, item):
            if isinstance(item, str):
                item = item.upper()
            return super().__getitem__(item)
    

    这假定您的枚举都是大写的。使用它非常简单:

    class Label(Enum, metaclass=CaseInsensitiveEnumMeta):
        REDAPPLE = 1
        GREENAPPLE = 2
    

    在这种情况下,我不确定您是否需要 Enum。这里要注意的是,您的枚举必须全部大写才能正常工作。如果您想进行真正不敏感的搜索,则必须确保 __members__ 中的所有键都正确折叠。

    在此期间,您可以这样做

    >>> Label['GreenApple']
    Label.GREENAPPLE
    

    【讨论】:

      【解决方案3】:

      enum 有 missing 函数,可以重写该函数以使 enum 不区分大小写。 根据文档 https://docs.python.org/3.11/howto/enum.html missing – 找不到值时使用的查找函数;可能会被覆盖

      示例

      class Status(enum.Enum):
         @classmethod
         def _missing_(cls, value):
            for member in cls:
               if member.value == value.upper():
                  return member
         SUCCESS = 'SUCCESS'
         FAILURE = 'FAILURE'
      
      print(Status('success'))
      

      输出

      状态.成功

      【讨论】:

        猜你喜欢
        • 2023-01-18
        • 2015-10-27
        • 2021-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-22
        • 1970-01-01
        • 2016-01-20
        相关资源
        最近更新 更多