OrenIshShalom
OrenIshShalom

Reputation: 7112

Idiomatic way to check if a value is inside an Enum

I want to check if some string value exists in the values set of some Enum. Here is what I do:

from enum import Enum

class Color(str, Enum):

    RED = "red"
    GREEN = "green"
    YELLOW = "yellow"

s = "red"
# s = "blue"

if any(s == c.value for c in Color):
    print(Color(s))

When I checked the documentation I found that:

The EnumMeta metaclass is responsible for providing the contains(), dir(), iter() and other methods that allow one to do things with an Enum class that fail on a typical class, such as list(Color) or some_enum_var in Color

But I want something different (checking existence for values). Is there a more pythonic way to solve this?

Upvotes: 3

Views: 2922

Answers (4)

Milind Chaudhary
Milind Chaudhary

Reputation: 1730

Just convert it into value list and check

"red" in [item.value for item in Color]

Upvotes: 1

OrenIshShalom
OrenIshShalom

Reputation: 7112

Here is a slightly more aesthetic implementation based on blhsing's answer:

from enum import Enum

class Color(str, Enum):

    RED = "red"
    GREEN = "green"
    YELLOW = "yellow"

    @staticmethod
    def values():
        # provide a meaningful named getter
        return Color._value2member_map_

s = "green"
# s = "blue"

# actual use becomes more clear
if s in Color.values():
    print(Color(s))

Upvotes: 2

blhsing
blhsing

Reputation: 106553

You can test values against _value2member_map_, a dict attribute of the Enum sub-class that maps values to member classes, if you prefer not to clutter up your code with a try-except block:

if s in Color._value2member_map_:
    print(Color(s))

Upvotes: 2

Samwise
Samwise

Reputation: 71454

In Python 3.12 you'll be able to do this directly with in:

>>> "red" in Color
<stdin>:1: DeprecationWarning: in 3.12 __contains__ will no longer raise TypeError, but will return True if
obj is a member or a member's value
...
TypeError: unsupported operand type(s) for 'in': 'str' and 'EnumMeta'

While we're waiting for that, though, one option in addition to the one you've already found is to pass your value to the constructor, which will return the appropriate enum instance if there's a matching value, and raise ValueError otherwise.

>>> Color("red")
<Color.RED: 'red'>
>>> Color("asdf")
Traceback (most recent call last):
...
ValueError: 'asdf' is not a valid Color

Upvotes: 4

Related Questions