153

How can I implement an enumeration type (spelled enum in some languages) in Python? What is the common practice to get this functionality?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • 18
    Now there is a standard Enum type in Python 3.4. Read this post: http://stackoverflow.com/questions/16653129/future-compatible-enums-in-2-7 – Javier Apr 01 '14 at 15:17
  • 4
    Here is the PEP for the enum type that is now in Python: https://www.python.org/dev/peps/pep-0435/ – shuttle87 Jul 27 '15 at 02:22

4 Answers4

375
class Materials:
    Shaded, Shiny, Transparent, Matte = range(4)

>>> print Materials.Matte
3

Update: For Python 3.4+:

As of Python 3.4+, you can now use Enum (or IntEnum for enums with int values) from the enum module. Use enum.auto to increment the values up automatically:

import enum


class Materials(enum.IntEnum):
    Shaded = 1
    Shiny = enum.auto()
    Transparent = 3
    Matte = enum.auto()


print(Materials.Shiny == 2)  # True
print(Materials.Matte == 4)  # True
Community
  • 1
  • 1
Van Gale
  • 43,536
  • 9
  • 71
  • 81
  • 17
    I haven't seen that one before, good stuff. – Ben Blank Mar 31 '09 at 20:56
  • The only problem is I need the first item to be 1. Is that possible to do with your method? – Joan Venge Mar 31 '09 at 21:41
  • Of all the methods i've seen, this is probably my favorite. Very elegant! – goldenratio Mar 31 '09 at 22:31
  • 4
    @Joan You could do `_unused, Shaded, Shiny, Transparent, Matte = range(5)` – zekel Dec 09 '10 at 02:12
  • 83
    Kinda late, but you can also do `Shaded, Shiny, Transparent, Matte = range(1, 5)` if you don't like having the `_unused` there – Davy8 Jan 30 '11 at 17:42
  • 3
    You also don't have to use range, assigning each class variable a value individually. – bret Jun 13 '12 at 22:38
  • 4
    Unfortunately, this method of making an enum is incomplete, as the enums cannot be iterated over, nor is each value an unique type (e.g. just an int). – Gewthen Jun 10 '15 at 01:43
  • @Gewthen In many languages, enums are "just an int". Isn't that more or less expected? If necessary, you could implement an appropriate [iterator](http://stackoverflow.com/a/231855/1796585). – Mads Y Sep 02 '15 at 18:52
  • @MadsY In other languages they are simply syntactic sugar, whereas in other languages (e.g. Python3) they are not. Having a strong type for your values is generally better in strongly types languages, because it utilizes the language more. If they are only just numbers it's more to remember when debugging or looking at logs. I'd rather just see `Materials.shinny` in a log than `1` because `1` tells me much less than `Materials.shinny` – Gewthen Oct 17 '15 at 05:26
  • 9
    This should be updated to add that `enums` are in Python as of 3.4 – SudoKid Jan 04 '17 at 00:38
21

I've seen this pattern several times:

>>> class Enumeration(object):
        def __init__(self, names):  # or *names, with no .split()
            for number, name in enumerate(names.split()):
                setattr(self, name, number)

>>> foo = Enumeration("bar baz quux")
>>> foo.quux
2

You can also just use class members, though you'll have to supply your own numbering:

>>> class Foo(object):
        bar  = 0
        baz  = 1
        quux = 2

>>> Foo.quux
2

If you're looking for something more robust (sparse values, enum-specific exception, etc.), try this recipe.

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
Ben Blank
  • 54,908
  • 28
  • 127
  • 156
9

I have no idea why Enums are not support natively by Python. The best way I've found to emulate them is by overridding _ str _ and _ eq _ so you can compare them and when you use print() you get the string instead of the numerical value.

class enumSeason():
    Spring = 0
    Summer = 1
    Fall = 2
    Winter = 3
    def __init__(self, Type):
        self.value = Type
    def __str__(self):
        if self.value == enumSeason.Spring:
            return 'Spring'
        if self.value == enumSeason.Summer:
            return 'Summer'
        if self.value == enumSeason.Fall:
            return 'Fall'
        if self.value == enumSeason.Winter:
            return 'Winter'
    def __eq__(self,y):
       return self.value==y.value

Usage:

>>> s = enumSeason(enumSeason.Spring)

>>> print(s)

Spring
Spell
  • 384
  • 4
  • 11
  • 4
    PEP354 has a rejection notice. See http://www.python.org/dev/peps/pep-0354/#rejection-notice – Fred Larson Mar 31 '09 at 20:33
  • 4
    It would be quicker to have a class dictionary {"Spring": 0, "Summer":1, ...} and use __init__ to iterate through entries and set attributes, because then __str__ could just look the value up rather than being coded by hand for every case. – Charles J. Daniels Mar 29 '15 at 08:51
  • 2
    See this: https://www.python.org/dev/peps/pep-0435/ – shuttle87 Jul 27 '15 at 02:22
6

You could probably use an inheritance structure although the more I played with this the dirtier I felt.

class AnimalEnum:
  @classmethod
  def verify(cls, other):
    return issubclass(other.__class__, cls)


class Dog(AnimalEnum):
  pass

def do_something(thing_that_should_be_an_enum):
  if not AnimalEnum.verify(thing_that_should_be_an_enum):
    raise OhGodWhy
Trey Stout
  • 6,231
  • 3
  • 24
  • 27