What is enum and why we need it
An enumerated type, a.k.a. 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 example, a
COLOR enum may include named values such as
BLUE. Notice all the named values are written in capital form to distinguish them as constants, which are significantly different from variables.
So, why do we need to use an enum? Imagine a scenario where you may want to limit the type of gender for users in a website to
N/A. Of course, a list of strings will do the job just fine like
user.gender = 'MALE' or
user.gender = 'FEMALE'. However, using a string as a value for the gender attribute is not robust to programmer errors and malicious attacks. A programmer could easily mistype ‘MALE’ to ‘ALE’ or ‘FEMALE’ to ‘EMAIL’ and the code would still run and produce funny but terrible results. An attacker may provide carefully constructed garbage string values to the system, trying to cause a crash or gain root access. If we use an enum to restrict the
user.gender attribute to a limited list of values, none of the aforementioned problems will happen.
Python enum the easy way
In Python, the built-in function
type accepts one or three arguments. According to the Python documentation, When you pass one argument to
type, it returns the type of an object. When you pass three arguments to
type as in
type(name, bases, dict):
It returns a new type object. This is essentially a dynamic form of the
classstatement. The first argument
namestring is the class name. The second argument
basestuple specifies the base classes of the new type. The third argument
dictis the namespace containing definitions for class body.
type, we can construct an
enum in the following way:
>>> def enum(**named_values): ... return type('Enum', (), named_values) ... >>> Color = enum(RED='red', GREEN='green', BLUE='blue') >>> Color.RED 'red' >>> Color.GREEN 'green' >>> Gender = enum(MALE='male', FEMALE='female', N_A='n/a') >>> Gender.N_A 'n/a' >>> Gender.MALE 'male'
Gender are classes that behaves like
enum and you could use them in the following way:
>>> 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 ... >>> u = User('malicious string') Traceback (most recent call last): File "", line 1, in File "", line 4, in __init__ ValueError: gender not valid
Notice the invalid string passed-in gets rejected by the constructor of
Python enum the fancy way
Although the previous way of implementing
enum is easy, it does require you to explicitly specify a value for each
named value. For example, in
enum(MALE='male', FEMALE='female', N_A='n/a'),
MALE is a the name and
'male' is the value for that name. Since most of the time we only use
enum by its names, we can implement an
enum that does automatic value assignment in the following way:
>>> def enum(*args): ... enums = dict(zip(args, range(len(args)))) ... return type('Enum', (), enums) ... >>> Gender = enum('MALE', 'FEMALE', 'N_A') >>> Gender.N_A 2 >>> Gender.MALE 0
range, the code automatically assigns an integer value to each
Tips and Suggestions for Python enums
enumhelps limit the exposed choices of values for an attribute, which could be very useful in real-world programming. When dealing with databases, an
enumthat is identical across Python and the database management system could prevent lots of hard-to-find bugs.
- Using an
enumto safe guard your system against malicious input. Always check the input values before accepting them into your system.