How to use Python Enums.
In a Nutshell
Here are a few quick examples of how to use Enums in Python.
Create an EntityType enum and get a list of its members thus:
>>> from enum import Enum >>> EntityType = Enum('EntityType', ['Person', 'Organization', 'Location']) >>> list(EntityType) [<EntityType.Person: 1>, <EntityType.Organization: 2>, <EntityType.Location: 3>]
If for some reason you want the values to begin at 0, use the start
parameter:
>>> EntityType = Enum('EntityType', ['Person', 'Organization', 'Location'], start=0) >>> list(EntityType) [<EntityType.Person: 0>, <EntityType.Organization: 1>, <EntityType.Location: 2>]
Use the class keyword to create an enum with more complicated properties like methods.
>>> from enum import Enum >>> class Color(Enum): ... RED = 1 ... GREEN = 2 ... BLUE = 3 ...
Get a string representation of an Enum member by using its name:
>>> EntityType.Person.name 'Person'
Or use str() to get a fuller name:
>>> str(EntityType.Person) 'EntityType.Person'
Use square brackets to create an enum member from a string:
>>> enumObject = EntityType['Person'] >>> enumObject <EntityType.Person: 1>
To test whether a string is a valid enum member, you have two options.
- Option 1 is to try to create an enum object from it, and handle the exception.
>>> enumObject = EntityType['Pearson'] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.5/enum.py", line 277, in __getitem__ return cls._member_map_[name] KeyError: 'Pearson'
- Option 2 is to use list comprehension to get a list of each enum attribute's 'name' property, and then test whether your string is in that list.
>>> 'Pearson' in [x.name for x in list(EntityType)] False >>> 'Person' in [x.name for x in list(EntityType)] True
Use isinstance() to assert that an object is a specific type of an enum:
>>> enumObject = EntityType.Organization >>> isinstance(enumObject, EntityType)
Use is or == to assert that an enum object is a particular enum member:
>>> enumObject = EntityType.Location >>> enumObject is EntityType.Person False >>> enumObject is EntityType.Location True >>> enumObject == EntityType.Location True
Here's how you iterate through all the members of an enum:
>>> members = [] >>> for item in EntityType: ... members.append(item.name) ... >>> members ['Person', 'Organization', 'Location']
Details
I still have much to learn about being "pythonic," so perhaps here I'm only revealing my ignorance. But it seems to me that too much Python code uses strings when enums are really what is called for.
Enums are superior to strings in at least two ways:
- They provide automatic error checking. Its easy to to type "Yallow" when you mean "Yellow," or "Febuary" when you mean "February." Enums save you from making those kinds of mistakes.
- If you decide to rename an enum member, you'll save yourself much time and possibly errors by using an enum instead of a string. Especially if you use an IDE and it has refactoring functionality—in which case it's a breeze.
Nomenclature
The Python enum documentation provides a much-needed guide to enum nomenclature. Here I borrow heavily from the documentation—at points even crossing into outright plagiarism.
>>> from enum import Enum >>> class Color(Enum): ... RED = 1 ... GREEN = 2 ... BLUE = 3 ...
In the example above:
Color
is an enum or enumeration.Color.RED
is an attribute.- The attributes
Color.RED
andColor.GREEN
are enum members (or enumeration members). - Each enum member has a name and a value. The name of
Color.RED
isRED
, and its value is1
.
Get enum from value
Sometimes enum values are meaningless. But sometimes they are meaningful in the sense that enumeration members can be greater or less than one another.
>>> Quality = Enum('Quality', ['VeryLow', 'Low', 'Medium', 'High', 'VeryHigh']) >>> Quality.Low.value < Quality.VeryHigh.value True >>> Quality.Medium.value > Quality.High.value False
Let's say that you have an object that has a Quality component.
>>> class Car(object): ... def __init__(self, quality): ... self.quality = quality ... >>> myCar = Car(Quality.VeryHigh) >>> myCar.quality <Quality.VeryHigh: 5>
Suppose now that you want to reduce that object's quality by two degrees. In other words, if its Quality is VeryHigh, you want to change the Quality to Medium; and if Medium, you want to set it to VeryLow. To do this you will need to be able to set the quality using the enum's value. You do this in the following manner:
>>> myCar.quality = Quality(myCar.quality.value - 2) >>> myCar.quality <Quality.Medium: 3>
External Resources
Check out http://xion.io/post/code/python-enums-are-ok.html for a good posting about enums in Python.
A Regret
I can't leave the topic of enums without expressing this regret: I would really like auto-complete to work for enums in Python, as it does in Java. Alas, it doesn't seem to—neither in Eclipse's PyDev nor in JetBrains' PyCharm.