Insights from Our Experts

Blog image

Implementing Enum in Python

Author Image

Nakul Narayanan,Software Engineer

Enum is a data type consisting of a set of named values called elements, members or enumerators of the type. These enumerated named values function as constants in the computing language. For instance a Color enum many include named values like Red, Green and Yellow. 

 

Enumerations in Python are implemented by using the module named ‘enum’. Enumerations are created using classes. Enums have names and values associated with them.

 

Installation

Python 3.x has built in type enum. Otherwise
pip install enum34

 

For creating an enumerated type Card

# Importing enum
import enum

class Cards(enum.Enum):
“””
Creating enumerations
“””
Club = 1
Diamond = 2
Heart = 3
Spade = 4

 

Or enum could be directly invoked as

 

Cards = Enum('Cards', ['Club', 'Diamond', 'Heart','Spade'], start=1)

 

where Cards will be the enum name and ['Club', 'Diamond', 'Heart','Spade'] will be the enum members, They could be list or name-value pairs or dict.Unless value is not specified the default values will be the lidt indices (the start indices could be specified explicitly by setting start parameter)


>>> Cards.Club
<Cards.Club: 1>

 

Accessing enum values

Enum members could be accessed by 2 ways


1. By name: In this method, the name of enum member is passed.

print (Cards(2).name >> Diamond)

 

2. By value: In this method, the value of enum member is passed.

print (Cards.Diamond.value >>2)

 

Comparison:

1. Identity:- These are checked using keywords “is” and “is not“.
2. Equality:- Equality comparisons of “==” and “!=” types are also supported.


Iteration:

  • list(Cards)

Output as

[<Cards.Club: 1>, <Cards.Diamond: 2>, <Cards.Heart: 3>, <Cards.Spade: 4>]

 

  • The special attribute __members__ is an ordered dictionary mapping names to members. It includes all names defined in the enumeration
for name, member in Cards.__members__.items():
    name, member

 

output:

('Club', <Cards.Club: 1>)
('Diamond', <Cards.Diamond: 2>)
('Heart', <Cards.Heart : 3>)
('Spade', <Cards.Spade : 4>)

 

Uniqueness in value

If enum members are required to have unique value assignment then @unique is added. ValueError exception will be raised if member value repeats.


Pythonic programmatic way for enum creation

Rather than hardcoding the enum in class definition,

def enum(**named_values):
    return type('Enum', (), named_values)
Cards = enum(CLUB='club', DIAMOND='Diamond', HEART='Heart',SPADE= Spade)
class User(object):
    def __init__(self, gender):
        if gender not in (Gender.MALE, Gender.FEMALE, Gender.N_A):
        raise ValueError('gender not valid')
        self.gender = gender

 

A small comparison between the earlier and enum usage

class Certificate(Model):
   Permanent= 1
   Temporary= 2
   In_progress= 3
   status= frozenset([PERMANENT, TEMPORARY, IN_PROGRESS])
   
   author= StringProperty()
   text= TextProperty()
   state= String(choices=STATES)
#usage
certificate= Certificate(author="Xion", text="Hey")
certificate.state= Certificate. In_progress
certificate.save()

 

Converting it to use enum

class Certificate(Model):
   class Status(Enum):
       Permanent= 1
       Temporary= 2 
       In_progress= 3
   author= StringProperty()
   text= TextProperty()
   state= StringProperty(choices=[s.value for s in Status])
certificate= Certificate(author="Xion", text="Meh.")
certificate.state= Certificate.Status.In_progress.value
certificate.save()


Advantageous of using enum

  1. If you use enums instead of integers (or String codes), you increase compile-time checking and avoid errors from passing in invalid constants, and you document which values are legal to use.
  2. Enums are not allocated in memory. They only exists in compilation stage.
  3. A new developer could easily understand the variable type and the values that could be allocated for that variable. It will be clearer. 
  4. Readability
  5. If any error is present, it'll be seen in compile time itself.
  6. An enum that is identical across Python and the database management system could prevent lots of hard-to-find bug.
  7. Always check the input values before accepting them into your system. It could resist malicious input. 

 

Note: Overuse of enums might mean that your methods do too much (it's often better to have several separate methods, rather than one method that takes several flags which modify what it does), but if you have to use flags or type codes, enums are the way to go.