pythonenums

How do I test if int value exists in Python Enum without using try/catch?


Using the Python Enum class, is there a way to test if an Enum contains a specific int value without using try/catch?

With the following class:

from enum import Enum

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

How can I test for the value 6 (returning true), or the value 7 (returning false)?


Solution

  • UPDATE

    my answer is outdated. for newer python versions see Filip Poplewski's answer.


    test for values

    variant 1

    note that an Enum has a member called _value2member_map_ (which is undocumented and may be changed/removed in future python versions):

    print(Fruit._value2member_map_)
    # {4: <Fruit.Apple: 4>, 5: <Fruit.Orange: 5>, 6: <Fruit.Pear: 6>}
    

    you can test if a value is in your Enum against this map:

    5 in Fruit._value2member_map_  # True
    7 in Fruit._value2member_map_  # False
    

    variant 2

    if you do not want to rely on this feature this is an alternative:

    values = [item.value for item in Fruit]  # [4, 5, 6]
    

    or (probably better): use a set; the in operator will be more efficient:

    values = set(item.value for item in Fruit)  # {4, 5, 6}
    

    then test with

    5 in values  # True
    7 in values  # False
    

    add has_value to your class

    you could then add this as a method to your class:

    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
    

    starting form python 3.9 (?) python offers IntEnum. with these you could do this:

    from enum import IntEnum
    
    class Fruit(IntEnum):
        Apple = 4
        Orange = 5
        Pear = 6
    
    print(6 in iter(Fruit))  # True
    

    note there is no need to create a list; just iterating over iter(Fruit) will do. again, if this is needed repeatedly it may be worth creating a set as above:

    values = set(Fruit)
    print(5 in values)  # True
    

    test for keys

    if you want to test for the names (and not the values) i would use _member_names_:

    'Apple' in Fruit._member_names_  # True
    'Mango' in Fruit._member_names_  # False