[python] How can I represent an 'Enum' in Python?

I'm mainly a C# developer, but I'm currently working on a project in Python.

How can I represent the equivalent of an Enum in Python?

This question is related to python python-3.x enums

The answer is


Following the Java like enum implementation proposed by Aaron Maenpaa, I came out with the following. The idea was to make it generic and parseable.

class Enum:
    #'''
    #Java like implementation for enums.
    #
    #Usage:
    #class Tool(Enum): name = 'Tool'
    #Tool.DRILL = Tool.register('drill')
    #Tool.HAMMER = Tool.register('hammer')
    #Tool.WRENCH = Tool.register('wrench')
    #'''

    name = 'Enum'    # Enum name
    _reg = dict([])   # Enum registered values

    @classmethod
    def register(cls, value):
        #'''
        #Registers a new value in this enum.
        #
        #@param value: New enum value.
        #
        #@return: New value wrapper instance.
        #'''
        inst = cls(value)
        cls._reg[value] = inst
        return inst

    @classmethod
    def parse(cls, value):
        #'''
        #Parses a value, returning the enum instance.
        #
        #@param value: Enum value.
        #
        #@return: Value corresp instance.        
        #'''
        return cls._reg.get(value)    

    def __init__(self, value):
        #'''
        #Constructor (only for internal use).
        #'''
        self.value = value

    def __str__(self):
        #'''
        #str() overload.
        #'''
        return self.value

    def __repr__(self):
        #'''
        #repr() overload.
        #'''
        return "<" + self.name + ": " + self.value + ">"

I prefer to define enums in Python like so:

class Animal:
  class Dog: pass
  class Cat: pass

x = Animal.Dog

It's more bug-proof than using integers since you don't have to worry about ensuring that the integers are unique (e.g. if you said Dog = 1 and Cat = 1 you'd be screwed).

It's more bug-proof than using strings since you don't have to worry about typos (e.g. x == "catt" fails silently, but x == Animal.Catt is a runtime exception).


The new standard in Python is PEP 435, so an Enum class will be available in future versions of Python:

>>> from enum import Enum

However to begin using it now you can install the original library that motivated the PEP:

$ pip install flufl.enum

Then you can use it as per its online guide:

>>> from flufl.enum import Enum
>>> class Colors(Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue

Keep it simple:

class Enum(object): 
    def __init__(self, tupleList):
            self.tupleList = tupleList

    def __getattr__(self, name):
            return self.tupleList.index(name)

Then:

DIRECTION = Enum(('UP', 'DOWN', 'LEFT', 'RIGHT'))
DIRECTION.DOWN
1

Use the following.

TYPE = {'EAN13':   u'EAN-13',
        'CODE39':  u'Code 39',
        'CODE128': u'Code 128',
        'i25':     u'Interleaved 2 of 5',}

>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']

I used that for Django model choices, and it looks very pythonic. It is not really an Enum, but it does the job.


What I use:

class Enum(object):
    def __init__(self, names, separator=None):
        self.names = names.split(separator)
        for value, name in enumerate(self.names):
            setattr(self, name.upper(), value)
    def tuples(self):
        return tuple(enumerate(self.names))

How to use:

>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))

So this gives you integer constants like state.PUBLISHED and the two-tuples to use as choices in Django models.


Another, very simple, implementation of an enum in Python, using namedtuple:

from collections import namedtuple

def enum(*keys):
    return namedtuple('Enum', keys)(*keys)

MyEnum = enum('FOO', 'BAR', 'BAZ')

or, alternatively,

# With sequential number values
def enum(*keys):
    return namedtuple('Enum', keys)(*range(len(keys)))

# From a dict / keyword args
def enum(**kwargs):
    return namedtuple('Enum', kwargs.keys())(*kwargs.values())




# Example for dictionary param:
values = {"Salad": 20, "Carrot": 99, "Tomato": "No i'm not"} 
Vegetables= enum(**values)

# >>> print(Vegetables.Tomato)        'No i'm not'


# Example for keyworded params: 
Fruits = enum(Apple="Steve Jobs", Peach=1, Banana=2)

# >>> print(Fruits.Apple)             'Steve Jobs'

Like the method above that subclasses set, this allows:

'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO

But has more flexibility as it can have different keys and values. This allows

MyEnum.FOO < MyEnum.BAR

to act as is expected if you use the version that fills in sequential number values.


Here's an approach with some different characteristics I find valuable:

  • allows > and < comparison based on order in enum, not lexical order
  • can address item by name, property or index: x.a, x['a'] or x[0]
  • supports slicing operations like [:] or [-1]

and most importantly prevents comparisons between enums of different types!

Based closely on http://code.activestate.com/recipes/413486-first-class-enums-in-python.

Many doctests included here to illustrate what's different about this approach.

def enum(*names):
    """
SYNOPSIS
    Well-behaved enumerated type, easier than creating custom classes

DESCRIPTION
    Create a custom type that implements an enumeration.  Similar in concept
    to a C enum but with some additional capabilities and protections.  See
    http://code.activestate.com/recipes/413486-first-class-enums-in-python/.

PARAMETERS
    names       Ordered list of names.  The order in which names are given
                will be the sort order in the enum type.  Duplicate names
                are not allowed.  Unicode names are mapped to ASCII.

RETURNS
    Object of type enum, with the input names and the enumerated values.

EXAMPLES
    >>> letters = enum('a','e','i','o','u','b','c','y','z')
    >>> letters.a < letters.e
    True

    ## index by property
    >>> letters.a
    a

    ## index by position
    >>> letters[0]
    a

    ## index by name, helpful for bridging string inputs to enum
    >>> letters['a']
    a

    ## sorting by order in the enum() create, not character value
    >>> letters.u < letters.b
    True

    ## normal slicing operations available
    >>> letters[-1]
    z

    ## error since there are not 100 items in enum
    >>> letters[99]
    Traceback (most recent call last):
        ...
    IndexError: tuple index out of range

    ## error since name does not exist in enum
    >>> letters['ggg']
    Traceback (most recent call last):
        ...
    ValueError: tuple.index(x): x not in tuple

    ## enums must be named using valid Python identifiers
    >>> numbers = enum(1,2,3,4)
    Traceback (most recent call last):
        ...
    AssertionError: Enum values must be string or unicode

    >>> a = enum('-a','-b')
    Traceback (most recent call last):
        ...
    TypeError: Error when calling the metaclass bases
        __slots__ must be identifiers

    ## create another enum
    >>> tags = enum('a','b','c')
    >>> tags.a
    a
    >>> letters.a
    a

    ## can't compare values from different enums
    >>> letters.a == tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    >>> letters.a < tags.a
    Traceback (most recent call last):
        ...
    AssertionError: Only values from the same enum are comparable

    ## can't update enum after create
    >>> letters.a = 'x'
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'a' is read-only

    ## can't update enum after create
    >>> del letters.u
    Traceback (most recent call last):
        ...
    AttributeError: 'EnumClass' object attribute 'u' is read-only

    ## can't have non-unique enum values
    >>> x = enum('a','b','c','a')
    Traceback (most recent call last):
        ...
    AssertionError: Enums must not repeat values

    ## can't have zero enum values
    >>> x = enum()
    Traceback (most recent call last):
        ...
    AssertionError: Empty enums are not supported

    ## can't have enum values that look like special function names
    ## since these could collide and lead to non-obvious errors
    >>> x = enum('a','b','c','__cmp__')
    Traceback (most recent call last):
        ...
    AssertionError: Enum values beginning with __ are not supported

LIMITATIONS
    Enum values of unicode type are not preserved, mapped to ASCII instead.

    """
    ## must have at least one enum value
    assert names, 'Empty enums are not supported'
    ## enum values must be strings
    assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
        isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
    ## enum values must not collide with special function names
    assert len([i for i in names if i.startswith("__")]) == 0,\
        'Enum values beginning with __ are not supported'
    ## each enum value must be unique from all others
    assert names == uniquify(names), 'Enums must not repeat values'

    class EnumClass(object):
        """ See parent function for explanation """

        __slots__ = names

        def __iter__(self):
            return iter(constants)

        def __len__(self):
            return len(constants)

        def __getitem__(self, i):
            ## this makes xx['name'] possible
            if isinstance(i, types.StringTypes):
                i = names.index(i)
            ## handles the more normal xx[0]
            return constants[i]

        def __repr__(self):
            return 'enum' + str(names)

        def __str__(self):
            return 'enum ' + str(constants)

        def index(self, i):
            return names.index(i)

    class EnumValue(object):
        """ See parent function for explanation """

        __slots__ = ('__value')

        def __init__(self, value):
            self.__value = value

        value = property(lambda self: self.__value)

        enumtype = property(lambda self: enumtype)

        def __hash__(self):
            return hash(self.__value)

        def __cmp__(self, other):
            assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
            return cmp(self.value, other.value)

        def __invert__(self):
            return constants[maximum - self.value]

        def __nonzero__(self):
            ## return bool(self.value)
            ## Original code led to bool(x[0])==False, not correct
            return True

        def __repr__(self):
            return str(names[self.value])

    maximum = len(names) - 1
    constants = [None] * len(names)
    for i, each in enumerate(names):
        val = EnumValue(i)
        setattr(EnumClass, each, val)
        constants[i] = val
    constants = tuple(constants)
    enumtype = EnumClass()
    return enumtype

The best solution for you would depend on what you require from your fake enum.

Simple enum:

If you need the enum as only a list of names identifying different items, the solution by Mark Harrison (above) is great:

Pen, Pencil, Eraser = range(0, 3)

Using a range also allows you to set any starting value:

Pen, Pencil, Eraser = range(9, 12)

In addition to the above, if you also require that the items belong to a container of some sort, then embed them in a class:

class Stationery:
    Pen, Pencil, Eraser = range(0, 3)

To use the enum item, you would now need to use the container name and the item name:

stype = Stationery.Pen

Complex enum:

For long lists of enum or more complicated uses of enum, these solutions will not suffice. You could look to the recipe by Will Ware for Simulating Enumerations in Python published in the Python Cookbook. An online version of that is available here.

More info:

PEP 354: Enumerations in Python has the interesting details of a proposal for enum in Python and why it was rejected.


I use a metaclass to implement an enumeration (in my thought, it is a const). Here is the code:

class ConstMeta(type):
    '''
    Metaclass for some class that store constants
    '''
    def __init__(cls, name, bases, dct):
        '''
        init class instance
        '''
        def static_attrs():
            '''
            @rtype: (static_attrs, static_val_set)
            @return: Static attributes in dict format and static value set
            '''
            import types
            attrs = {}
            val_set = set()
            #Maybe more
            filter_names = set(['__doc__', '__init__', '__metaclass__', '__module__', '__main__'])
            for key, value in dct.iteritems():
                if type(value) != types.FunctionType and key not in filter_names:
                    if len(value) != 2:
                        raise NotImplementedError('not support for values that is not 2 elements!')
                    #Check value[0] duplication.
                    if value[0] not in val_set:
                        val_set.add(value[0])
                    else:
                        raise KeyError("%s 's key: %s is duplicated!" % (dict([(key, value)]), value[0]))
                    attrs[key] = value
            return attrs, val_set

        attrs, val_set = static_attrs()
        #Set STATIC_ATTRS to class instance so that can reuse
        setattr(cls, 'STATIC_ATTRS', attrs)
        setattr(cls, 'static_val_set', val_set)
        super(ConstMeta, cls).__init__(name, bases, dct)

    def __getattribute__(cls, name):
        '''
        Rewrite the special function so as to get correct attribute value
        '''
        static_attrs = object.__getattribute__(cls, 'STATIC_ATTRS')
        if name in static_attrs:
            return static_attrs[name][0]
        return object.__getattribute__(cls, name)

    def static_values(cls):
        '''
        Put values in static attribute into a list, use the function to validate value.
        @return: Set of values
        '''
        return cls.static_val_set

    def __getitem__(cls, key):
        '''
        Rewrite to make syntax SomeConstClass[key] works, and return desc string of related static value.
        @return: Desc string of related static value
        '''
        for k, v in cls.STATIC_ATTRS.iteritems():
            if v[0] == key:
                return v[1]
        raise KeyError('Key: %s does not exists in %s !' % (str(key), repr(cls)))


class Const(object):
    '''
    Base class for constant class.

    @usage:

    Definition: (must inherit from Const class!
        >>> class SomeConst(Const):
        >>>   STATUS_NAME_1 = (1, 'desc for the status1')
        >>>   STATUS_NAME_2 = (2, 'desc for the status2')

    Invoke(base upper SomeConst class):
    1) SomeConst.STATUS_NAME_1 returns 1
    2) SomeConst[1] returns 'desc for the status1'
    3) SomeConst.STATIC_ATTRS returns {'STATUS_NAME_1': (1, 'desc for the status1'), 'STATUS_NAME_2': (2, 'desc for the status2')}
    4) SomeConst.static_values() returns set([1, 2])

    Attention:
    SomeCosnt's value 1, 2 can not be duplicated!
    If WrongConst is like this, it will raise KeyError:
    class WrongConst(Const):
        STATUS_NAME_1 = (1, 'desc for the status1')
        STATUS_NAME_2 = (1, 'desc for the status2')
    '''
    __metaclass__ = ConstMeta
##################################################################
#Const Base Class ends
##################################################################


def main():
    class STATUS(Const):
        ERROR = (-3, '??')
        OK = (0, '??')

    print STATUS.ERROR
    print STATUS.static_values()
    print STATUS.STATIC_ATTRS

    #Usage sample:
    user_input = 1
    #Validate input:
    print user_input in STATUS.static_values()
    #Template render like:
    print '<select>'
    for key, value in STATUS.STATIC_ATTRS.items():
        print '<option value="%s">%s</option>' % (value[0], value[1])
    print '</select>'


if __name__ == '__main__':
    main()

Python doesn't have a built-in equivalent to enum, and other answers have ideas for implementing your own (you may also be interested in the over the top version in the Python cookbook).

However, in situations where an enum would be called for in C, I usually end up just using simple strings: because of the way objects/attributes are implemented, (C)Python is optimized to work very fast with short strings anyway, so there wouldn't really be any performance benefit to using integers. To guard against typos / invalid values you can insert checks in selected places.

ANIMALS = ['cat', 'dog', 'python']

def take_for_a_walk(animal):
    assert animal in ANIMALS
    ...

(One disadvantage compared to using a class is that you lose the benefit of autocomplete)


Here is a variant on Alec Thomas's solution:

def enum(*args, **kwargs):
    return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs)) 

x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1

Alexandru's suggestion of using class constants for enums works quite well.

I also like to add a dictionary for each set of constants to lookup a human-readable string representation.

This serves two purposes: a) it provides a simple way to pretty-print your enum and b) the dictionary logically groups the constants so that you can test for membership.

class Animal:    
  TYPE_DOG = 1
  TYPE_CAT = 2

  type2str = {
    TYPE_DOG: "dog",
    TYPE_CAT: "cat"
  }

  def __init__(self, type_):
    assert type_ in self.type2str.keys()
    self._type = type_

  def __repr__(self):
    return "<%s type=%s>" % (
        self.__class__.__name__, self.type2str[self._type].upper())

Why must enumerations be ints? Unfortunately, I can't think of any good looking construct to produce this without changing the Python language, so I'll use strings:

class Enumerator(object):
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        if self.name == other:
            return True
        return self is other

    def __ne__(self, other):
        if self.name != other:
            return False
        return self is other

    def __repr__(self):
        return 'Enumerator({0})'.format(self.name)

    def __str__(self):
        return self.name

class Enum(object):
    def __init__(self, *enumerators):
        for e in enumerators:
            setattr(self, e, Enumerator(e))
    def __getitem__(self, key):
        return getattr(self, key)

Then again maybe it's even better now that we can naturally test against strings, for the sake of configuration files or other remote input.

Example:

class Cow(object):
    State = Enum(
        'standing',
        'walking',
        'eating',
        'mooing',
        'sleeping',
        'dead',
        'dying'
    )
    state = State.standing

In [1]: from enum import Enum

In [2]: c = Cow()

In [3]: c2 = Cow()

In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))

In [5]: c.state == c2.state
Out[5]: True

In [6]: c.State.mooing
Out[6]: Enumerator(mooing)

In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)

In [8]: c.state = Cow.State.dead

In [9]: c.state == c2.state
Out[9]: False

In [10]: c.state == Cow.State.dead
Out[10]: True

In [11]: c.state == 'dead'
Out[11]: True

In [12]: c.state == Cow.State['dead']
Out[11]: True

def enum(*sequential, **named):
    enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
    return type('Enum', (), enums)

If you name it, is your problem, but if not creating objects instead of values allows you to do this:

>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False

When using other implementations sited here (also when using named instances in my example) you must be sure you never try to compare objects from different enums. For here's a possible pitfall:

>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True

Yikes!


I have had occasion to need of an Enum class, for the purpose of decoding a binary file format. The features I happened to want is concise enum definition, the ability to freely create instances of the enum by either integer value or string, and a useful representation. Here's what I ended up with:

>>> class Enum(int):
...     def __new__(cls, value):
...         if isinstance(value, str):
...             return getattr(cls, value)
...         elif isinstance(value, int):
...             return cls.__index[value]
...     def __str__(self): return self.__name
...     def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
...     class __metaclass__(type):
...         def __new__(mcls, name, bases, attrs):
...             attrs['__slots__'] = ['_Enum__name']
...             cls = type.__new__(mcls, name, bases, attrs)
...             cls._Enum__index = _index = {}
...             for base in reversed(bases):
...                 if hasattr(base, '_Enum__index'):
...                     _index.update(base._Enum__index)
...             # create all of the instances of the new class
...             for attr in attrs.keys():
...                 value = attrs[attr]
...                 if isinstance(value, int):
...                     evalue = int.__new__(cls, value)
...                     evalue._Enum__name = attr
...                     _index[value] = evalue
...                     setattr(cls, attr, evalue)
...             return cls
... 

A whimsical example of using it:

>>> class Citrus(Enum):
...     Lemon = 1
...     Lime = 2
... 
>>> Citrus.Lemon
Citrus.Lemon
>>> 
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
...     Apple = 3
...     Banana = 4
... 
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True

Key features:

  • str(), int() and repr() all produce the most useful output possible, respectively the name of the enumartion, its integer value, and a Python expression that evaluates back to the enumeration.
  • Enumerated values returned by the constructor are limited strictly to the predefined values, no accidental enum values.
  • Enumerated values are singletons; they can be strictly compared with is

davidg recommends using dicts. I'd go one step further and use sets:

months = set('January', 'February', ..., 'December')

Now you can test whether a value matches one of the values in the set like this:

if m in months:

like dF, though, I usually just use string constants in place of enums.


On 2013-05-10, Guido agreed to accept PEP 435 into the Python 3.4 standard library. This means that Python finally has builtin support for enumerations!

There is a backport available for Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4. It's on Pypi as enum34.

Declaration:

>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3

Representation:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

Iteration:

>>> for color in Color:
...   print(color)
...
Color.red
Color.green
Color.blue

Programmatic access:

>>> Color(1)
Color.red
>>> Color['blue']
Color.blue

For more information, refer to the proposal. Official documentation will probably follow soon.


From Python 3.4 there will be official support for enums. You can find documentation and examples here on Python 3.4 documentation page.

Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in Functional API. To define an enumeration, subclass Enum as follows:

from enum import Enum
class Color(Enum):
     red = 1
     green = 2
     blue = 3

Before PEP 435, Python didn't have an equivalent but you could implement your own.

Myself, I like keeping it simple (I've seen some horribly complex examples on the net), something like this ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum members are distinct from integers, and they are composed of a name and a value.

class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
# "DOG"

If you don't want to type the values, use the following shortcut:

class Animal(Enum):
    DOG, CAT = range(2)

Enum implementations can be converted to lists and are iterable. The order of its members is the declaration order and has nothing to do with their values. For example:

class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True

def enum( *names ):

    '''
    Makes enum.
    Usage:
        E = enum( 'YOUR', 'KEYS', 'HERE' )
        print( E.HERE )
    '''

    class Enum():
        pass
    for index, name in enumerate( names ):
        setattr( Enum, name, index )
    return Enum

The enum package from PyPI provides a robust implementation of enums. An earlier answer mentioned PEP 354; this was rejected but the proposal was implemented http://pypi.python.org/pypi/enum.

Usage is easy and elegant:

>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'

def M_add_class_attribs(attribs):
    def foo(name, bases, dict_):
        for v, k in attribs:
            dict_[k] = v
        return type(name, bases, dict_)
    return foo

def enum(*names):
    class Foo(object):
        __metaclass__ = M_add_class_attribs(enumerate(names))
        def __setattr__(self, name, value):  # this makes it read-only
            raise NotImplementedError
    return Foo()

Use it like this:

Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError

if you just want unique symbols and don't care about the values, replace this line:

__metaclass__ = M_add_class_attribs(enumerate(names))

with this:

__metaclass__ = M_add_class_attribs((object(), name) for name in names)

Hmmm... I suppose the closest thing to an enum would be a dictionary, defined either like this:

months = {
    'January': 1,
    'February': 2,
    ...
}

or

months = dict(
    January=1,
    February=2,
    ...
)

Then, you can use the symbolic name for the constants like this:

mymonth = months['January']

There are other options, like a list of tuples, or a tuple of tuples, but the dictionary is the only one that provides you with a "symbolic" (constant string) way to access the value.

Edit: I like Alexandru's answer too!


Here is one implementation:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

Here is its usage:

Animals = Enum(["DOG", "CAT", "HORSE"])

print(Animals.DOG)

I had need of some symbolic constants in pyparsing to represent left and right associativity of binary operators. I used class constants like this:

# an internal class, not intended to be seen by client code
class _Constants(object):
    pass


# an enumeration of constants for operator associativity
opAssoc = _Constants()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()

Now when client code wants to use these constants, they can import the entire enum using:

import opAssoc from pyparsing

The enumerations are unique, they can be tested with 'is' instead of '==', they don't take up a big footprint in my code for a minor concept, and they are easily imported into the client code. They don't support any fancy str() behavior, but so far that is in the YAGNI category.


I really like Alec Thomas' solution (http://stackoverflow.com/a/1695250):

def enum(**enums):
    '''simple constant "enums"'''
    return type('Enum', (object,), enums)

It's elegant and clean looking, but it's just a function that creates a class with the specified attributes.

With a little modification to the function, we can get it to act a little more 'enumy':

NOTE: I created the following examples by trying to reproduce the behavior of pygtk's new style 'enums' (like Gtk.MessageType.WARNING)

def enum_base(t, **enums):
    '''enums with a base class'''
    T = type('Enum', (t,), {})
    for key,val in enums.items():
        setattr(T, key, T(val))

    return T

This creates an enum based off a specified type. In addition to giving attribute access like the previous function, it behaves as you would expect an Enum to with respect to types. It also inherits the base class.

For example, integer enums:

>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True

Another interesting thing that can be done with this method is customize specific behavior by overriding built-in methods:

def enum_repr(t, **enums):
    '''enums with a base class and repr() output'''
    class Enum(t):
        def __repr__(self):
            return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)

    for key,val in enums.items():
        i = Enum(val)
        i._name = key
        setattr(Enum, key, i)

    return Enum



>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'

So, I agree. Let's not enforce type safety in Python, but I would like to protect myself from silly mistakes. So what do we think about this?

class Animal(object):
    values = ['Horse','Dog','Cat']

    class __metaclass__(type):
        def __getattr__(self, name):
            return self.values.index(name)

It keeps me from value-collision in defining my enums.

>>> Animal.Cat
2

There's another handy advantage: really fast reverse lookups:

def name_of(self, i):
    return self.values[i]

Here is a nice Python recipe that I found here: http://code.activestate.com/recipes/577024-yet-another-enum-for-python/

def enum(typename, field_names):
    "Create a new enumeration type"

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    d = dict((reversed(nv) for nv in enumerate(field_names)), __slots__ = ())
    return type(typename, (object,), d)()

Example Usage:

STATE = enum('STATE', 'GET_QUIZ, GET_VERSE, TEACH')

More details can be found on the recipe page.


It's funny, I just had a need for this the other day and I couldnt find an implementation worth using... so I wrote my own:

import functools

class EnumValue(object):
    def __init__(self,name,value,type):
        self.__value=value
        self.__name=name
        self.Type=type
    def __str__(self):
        return self.__name
    def __repr__(self):#2.6 only... so change to what ever you need...
        return '{cls}({0!r},{1!r},{2})'.format(self.__name,self.__value,self.Type.__name__,cls=type(self).__name__)

    def __hash__(self):
        return hash(self.__value)
    def __nonzero__(self):
        return bool(self.__value)
    def __cmp__(self,other):
        if isinstance(other,EnumValue):
            return cmp(self.__value,other.__value)
        else:
            return cmp(self.__value,other)#hopefully their the same type... but who cares?
    def __or__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} | {1.Name}'.format(self,other),self.Value|other.Value,self.Type)
    def __and__(self,other):
        if other is None:
            return self
        elif type(self) is not type(other):
            raise TypeError()
        return EnumValue('{0.Name} & {1.Name}'.format(self,other),self.Value&other.Value,self.Type)
    def __contains__(self,other):
        if self.Value==other.Value:
            return True
        return bool(self&other)
    def __invert__(self):
        enumerables=self.Type.__enumerables__
        return functools.reduce(EnumValue.__or__,(enum for enum in enumerables.itervalues() if enum not in self))

    @property
    def Name(self):
        return self.__name

    @property
    def Value(self):
        return self.__value

class EnumMeta(type):
    @staticmethod
    def __addToReverseLookup(rev,value,newKeys,nextIter,force=True):
        if value in rev:
            forced,items=rev.get(value,(force,()) )
            if forced and force: #value was forced, so just append
                rev[value]=(True,items+newKeys)
            elif not forced:#move it to a new spot
                next=nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,items,nextIter,False)
                rev[value]=(force,newKeys)
            else: #not forcing this value
                next = nextIter.next()
                EnumMeta.__addToReverseLookup(rev,next,newKeys,nextIter,False)
                rev[value]=(force,newKeys)
        else:#set it and forget it
            rev[value]=(force,newKeys)
        return value

    def __init__(cls,name,bases,atts):
        classVars=vars(cls)
        enums = classVars.get('__enumerables__',None)
        nextIter = getattr(cls,'__nextitr__',itertools.count)()
        reverseLookup={}
        values={}

        if enums is not None:
            #build reverse lookup
            for item in enums:
                if isinstance(item,(tuple,list)):
                    items=list(item)
                    value=items.pop()
                    EnumMeta.__addToReverseLookup(reverseLookup,value,tuple(map(str,items)),nextIter)
                else:
                    value=nextIter.next()
                    value=EnumMeta.__addToReverseLookup(reverseLookup,value,(str(item),),nextIter,False)#add it to the reverse lookup, but don't force it to that value

            #build values and clean up reverse lookup
            for value,fkeys in reverseLookup.iteritems():
                f,keys=fkeys
                for key in keys:
                    enum=EnumValue(key,value,cls)
                    setattr(cls,key,enum)
                    values[key]=enum
                reverseLookup[value]=tuple(val for val in values.itervalues() if val.Value == value)
        setattr(cls,'__reverseLookup__',reverseLookup)
        setattr(cls,'__enumerables__',values)
        setattr(cls,'_Max',max([key for key in reverseLookup] or [0]))
        return super(EnumMeta,cls).__init__(name,bases,atts)

    def __iter__(cls):
        for enum in cls.__enumerables__.itervalues():
            yield enum
    def GetEnumByName(cls,name):
        return cls.__enumerables__.get(name,None)
    def GetEnumByValue(cls,value):
        return cls.__reverseLookup__.get(value,(None,))[0]

class Enum(object):
    __metaclass__=EnumMeta
    __enumerables__=None

class FlagEnum(Enum):
    @staticmethod
    def __nextitr__():
        yield 0
        for val in itertools.count():
            yield 2**val

def enum(name,*args):
    return EnumMeta(name,(Enum,),dict(__enumerables__=args))

Take it or leave it, it did what I needed it to do :)

Use it like:

class Air(FlagEnum):
    __enumerables__=('None','Oxygen','Nitrogen','Hydrogen')

class Mammals(Enum):
    __enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))

This solution is a simple way of getting a class for the enumeration defined as a list (no more annoying integer assignments):

enumeration.py:

import new

def create(class_name, names):
    return new.classobj(
        class_name, (object,), dict((y, x) for x, y in enumerate(names))
    )

example.py:

import enumeration

Colors = enumeration.create('Colors', (
    'red',
    'orange',
    'yellow',
    'green',
    'blue',
    'violet',
))

An Enum class can be a one-liner.

class Enum(tuple): __getattr__ = tuple.index

How to use it (forward and reverse lookup, keys, values, items, etc.)

>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]

Python 2.7 and find_name()

Here is an easy-to-read implementation of the chosen idea with some helper methods, which perhaps are more Pythonic and cleaner to use than "reverse_mapping". Requires Python >= 2.7.

To address some comments below, Enums are quite useful to prevent spelling mistakes in code, e.g. for state machines, error classifiers, etc.

def Enum(*sequential, **named):
  """Generate a new enum type. Usage example:

  ErrorClass = Enum('STOP','GO')
  print ErrorClass.find_name(ErrorClass.STOP)
    = "STOP"
  print ErrorClass.find_val("STOP")
    = 0
  ErrorClass.FOO     # Raises AttributeError
  """
  enums = { v:k for k,v in enumerate(sequential) } if not named else named

  @classmethod
  def find_name(cls, val):
    result = [ k for k,v in cls.__dict__.iteritems() if v == val ]
    if not len(result):
        raise ValueError("Value %s not found in Enum" % val)
    return result[0]

  @classmethod
  def find_val(cls, n):
    return getattr(cls, n)

  enums['find_val'] = find_val
  enums['find_name'] = find_name
  return type('Enum', (), enums)

If you need the numeric values, here's the quickest way:

dog, cat, rabbit = range(3)

In Python 3.x you can also add a starred placeholder at the end, which will soak up all the remaining values of the range in case you don't mind wasting memory and cannot count:

dog, cat, rabbit, horse, *_ = range(100)

The solution that I usually use is this simple function to get an instance of a dynamically created class.

def enum(names):
    "Create a simple enumeration having similarities to C."
    return type('enum', (), dict(map(reversed, enumerate(
        names.replace(',', ' ').split())), __slots__=()))()

Using it is as simple as calling the function with a string having the names that you want to reference.

grade = enum('A B C D F')
state = enum('awake, sleeping, dead')

The values are just integers, so you can take advantage of that if desired (just like in the C language).

>>> grade.A
0
>>> grade.B
1
>>> grade.F == 4
True
>>> state.dead == 2
True

A variant (with support to get an enum value's name) to Alec Thomas's neat answer:

class EnumBase(type):
    def __init__(self, name, base, fields):
        super(EnumBase, self).__init__(name, base, fields)
        self.__mapping = dict((v, k) for k, v in fields.iteritems())
    def __getitem__(self, val):
        return self.__mapping[val]

def enum(*seq, **named):
    enums = dict(zip(seq, range(len(seq))), **named)
    return EnumBase('Enum', (), enums)

Numbers = enum(ONE=1, TWO=2, THREE='three')
print Numbers.TWO
print Numbers[Numbers.ONE]
print Numbers[2]
print Numbers['three']

I like to use lists or sets as enumerations. For example:

>>> packet_types = ['INIT', 'FINI', 'RECV', 'SEND']
>>> packet_types.index('INIT')
0
>>> packet_types.index('FINI')
1
>>>

While the original enum proposal, PEP 354, was rejected years ago, it keeps coming back up. Some kind of enum was intended to be added to 3.2, but it got pushed back to 3.3 and then forgotten. And now there's a PEP 435 intended for inclusion in Python 3.4. The reference implementation of PEP 435 is flufl.enum.

As of April 2013, there seems to be a general consensus that something should be added to the standard library in 3.4—as long as people can agree on what that "something" should be. That's the hard part. See the threads starting here and here, and a half dozen other threads in the early months of 2013.

Meanwhile, every time this comes up, a slew of new designs and implementations appear on PyPI, ActiveState, etc., so if you don't like the FLUFL design, try a PyPI search.


The typesafe enum pattern which was used in Java pre-JDK 5 has a number of advantages. Much like in Alexandru's answer, you create a class and class level fields are the enum values; however, the enum values are instances of the class rather than small integers. This has the advantage that your enum values don't inadvertently compare equal to small integers, you can control how they're printed, add arbitrary methods if that's useful and make assertions using isinstance:

class Animal:
   def __init__(self, name):
       self.name = name

   def __str__(self):
       return self.name

   def __repr__(self):
       return "<Animal: %s>" % self

Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")

>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False

A recent thread on python-dev pointed out there are a couple of enum libraries in the wild, including:


This is the best one I have seen: "First Class Enums in Python"

http://code.activestate.com/recipes/413486/

It gives you a class, and the class contains all the enums. The enums can be compared to each other, but don't have any particular value; you can't use them as an integer value. (I resisted this at first because I am used to C enums, which are integer values. But if you can't use it as an integer, you can't use it as an integer by mistake so overall I think it is a win.) Each enum is a unique value. You can print enums, you can iterate over them, you can test that an enum value is "in" the enum. It's pretty complete and slick.

Edit (cfi): The above link is not Python 3 compatible. Here's my port of enum.py to Python 3:

def cmp(a,b):
   if a < b: return -1
   if b < a: return 1
   return 0


def Enum(*names):
   ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!

   class EnumClass(object):
      __slots__ = names
      def __iter__(self):        return iter(constants)
      def __len__(self):         return len(constants)
      def __getitem__(self, i):  return constants[i]
      def __repr__(self):        return 'Enum' + str(names)
      def __str__(self):         return 'enum ' + str(constants)

   class EnumValue(object):
      __slots__ = ('__value')
      def __init__(self, value): self.__value = value
      Value = property(lambda self: self.__value)
      EnumType = property(lambda self: EnumType)
      def __hash__(self):        return hash(self.__value)
      def __cmp__(self, other):
         # C fans might want to remove the following assertion
         # to make all enums comparable by ordinal value {;))
         assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
         return cmp(self.__value, other.__value)
      def __lt__(self, other):   return self.__cmp__(other) < 0
      def __eq__(self, other):   return self.__cmp__(other) == 0
      def __invert__(self):      return constants[maximum - self.__value]
      def __nonzero__(self):     return bool(self.__value)
      def __repr__(self):        return str(names[self.__value])

   maximum = len(names) - 1
   constants = [None] * len(names)
   for i, each in enumerate(names):
      val = EnumValue(i)
      setattr(EnumClass, each, val)
      constants[i] = val
   constants = tuple(constants)
   EnumType = EnumClass()
   return EnumType


if __name__ == '__main__':
   print( '\n*** Enum Demo ***')
   print( '--- Days of week ---')
   Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
   print( Days)
   print( Days.Mo)
   print( Days.Fr)
   print( Days.Mo < Days.Fr)
   print( list(Days))
   for each in Days:
      print( 'Day:', each)
   print( '--- Yes/No ---')
   Confirmation = Enum('No', 'Yes')
   answer = Confirmation.No
   print( 'Your answer is not', ~answer)

I like the Java enum, that's how I do it in Python:

def enum(clsdef):
    class Enum(object):
        __slots__=tuple([var for var in clsdef.__dict__ if isinstance((getattr(clsdef, var)), tuple) and not var.startswith('__')])

        def __new__(cls, *args, **kwargs):
            if not '_the_instance' in cls.__dict__:
                cls._the_instance = object.__new__(cls, *args, **kwargs)
            return cls._the_instance

        def __init__(self):
            clsdef.values=lambda cls, e=Enum: e.values()
            clsdef.valueOf=lambda cls, n, e=self: e.valueOf(n)
            for ordinal, key in enumerate(self.__class__.__slots__):
                args=getattr(clsdef, key)
                instance=clsdef(*args)
                instance._name=key
                instance._ordinal=ordinal
                setattr(self, key, instance)

        @classmethod
        def values(cls):
            if not hasattr(cls, '_values'):
                cls._values=[getattr(cls, name) for name in cls.__slots__]
            return cls._values

        def valueOf(self, name):
            return getattr(self, name)

        def __repr__(self):
            return ''.join(['<class Enum (', clsdef.__name__, ') at ', str(hex(id(self))), '>'])

    return Enum()

Sample use:

i=2
@enum
class Test(object):
    A=("a",1)
    B=("b",)
    C=("c",2)
    D=tuple()
    E=("e",3)

    while True:
        try:
            F, G, H, I, J, K, L, M, N, O=[tuple() for _ in range(i)]
            break;
        except ValueError:
            i+=1

    def __init__(self, name="default", aparam=0):
        self.name=name
        self.avalue=aparam

All class variables are defined as a tuple, just like the constructor. So far, you can't use named arguments.


Didn't see this one in the list of answers, here is the one I whipped up. It allows the use of 'in' keyword and len() method:

class EnumTypeError(TypeError):
    pass

class Enum(object):
    """
    Minics enum type from different languages
    Usage:
    Letters = Enum(list('abc'))
    a = Letters.a
    print(a in Letters) # True
    print(54 in Letters) # False
    """
    def __init__(self, enums):
        if isinstance(enums, dict):
            self.__dict__.update(enums)
        elif isinstance(enums, list) or isinstance(enums, tuple):
            self.__dict__.update(**dict((v,k) for k,v in enumerate(enums)))
        else:
            raise EnumTypeError

    def __contains__(self, key):
        return key in self.__dict__.values()

    def __len__(self):
        return len(self.__dict__.values())


if __name__ == '__main__':
    print('Using a dictionary to create Enum:')
    Letters = Enum(dict((v,k) for k,v in enumerate(list('abcde'))))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    print('\nUsing a list to create Enum:')
    Letters = Enum(list('abcde'))
    a = Letters.a
    print('\tIs a in e?', a in Letters)
    print('\tIs 54 in e?', 54 in Letters)
    print('\tLength of Letters enum:', len(Letters))

    try:
        # make sure we raise an exception if we pass an invalid arg
        Failure = Enum('This is a Failure')
        print('Failure')
    except EnumTypeError:
        print('Success!')

Output:

Using a dictionary to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5

Using a list to create Enum:
        Is a in e? True
        Is 54 in e? False
        Length of Letters enum: 5
Success!

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to python-3.x

Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation Replace specific text with a redacted version using Python Upgrade to python 3.8 using conda "Permission Denied" trying to run Python on Windows 10 Python: 'ModuleNotFoundError' when trying to import module from imported package What is the meaning of "Failed building wheel for X" in pip install? How to downgrade python from 3.7 to 3.6 I can't install pyaudio on Windows? How to solve "error: Microsoft Visual C++ 14.0 is required."? Iterating over arrays in Python 3 How to upgrade Python version to 3.7?

Examples related to enums

Enums in Javascript with ES6 Check if value exists in enum in TypeScript Why Python 3.6.1 throws AttributeError: module 'enum' has no attribute 'IntFlag'? TypeScript enum to object array How can I loop through enum values for display in radio buttons? How to get all values from python enum class? Get enum values as List of String in Java 8 enum to string in modern C++11 / C++14 / C++17 and future C++20 Implementing Singleton with an Enum (in Java) Swift: Convert enum value to String?