7

As I am learning about the concepts in Python I came across this enum module. I tried the below code:

import enum


# Using enum class create enumerations
class Days(enum.Enum):
   Sun = 1
   Mon = "raj"
   Tue = 3
   Wed= 123
   Thur=12312312
   Fri=1312312
   Sat=12122135435

   
# print the enum member as a string
print("The enum member as a string is : ",end="")
print(Days.Mon)

# print the enum member as a repr
print("he enum member as a repr is : ",end="")
print(repr(Days.Sun))
print(repr(Days.fri))

# Check type of enum member
print("The type of enum member is : ",end ="")
print(type(Days.Mon))

# Accessing enums by names or values
print(Days['Mon'])
print(Days(3))
print(Days['thur'])
print(Days['thur'] == "thur")
print(Days(12122135435) == "sat" )

# print name of enum member
print("The name of enum member is : ",end ="")
print(Days.Tue.name)

Output:

Days.Mon
he enum member as a repr is : <Days.Sun: 1>
<Days.fri: 1312312>
The type of enum member is : <enum 'Days'>
Days.Mon
Days.Tue
Days.thur
False
False
The name of enum member is: Tue

Below is simple class and class variable access:

class Raj:

    yoo = 1
    boo = "raj"
    too = 213
    
print(Raj.yoo)
print(Raj.boo)
print(Raj.too)

class Materials:
    Shaded, Shiny, Transparent, Matte = range(1, 5)
    
print(Materials.Matte)
print(Materials.Transparent)

Output:

1
raj
213
4
3

I am not able to understand what is the use case of enum when we can simply use class variables and call them simply to get values. The enum function just returns what we ask for print and return the name if we call by value. As you can all see in the above code I tried to match the return Days['thur'] == "thur" I thought by calling like this it is returning the name but nope. So tried calling like Days(12122135435) == "sat" this so I can get the name of the value and can match. But nope.

I am very much confused about why it is defined and why it is used?

bad_coder
  • 11,289
  • 20
  • 44
  • 72
El_Dorado
  • 193
  • 2
  • 12

3 Answers3

8

The Enum type comes from languages like C and C++. The motivation is explained e.g. here:

An enum is a user-defined type consisting of a set of named constants called enumerators. The idea is that instead of using an int to represent a set of values, a type with a restricted set of values is used instead. ... The problem with [using integers for representing rainbow colors] is that there are many more ints than colors. If violet has the value 7, and the program assigns a value of 15 to a variable, then it is clearly a bug - but might not be detected, as 15 is a valid value for an int. ... Using enums increase the level of abstraction and lets the programmer think about what the values mean rather than worry about how they are stored and accessed. This reduces the occurrence of bugs.

Enums have these benefits:

  • They restrict the values that the enum variable can take.
  • They force you to think about all the possible values that the enum can take.
  • They are a constant rather than a number, increasing readability of the source code

Traffic lights are a nice example:

from enum import Enum   

class TrafficLights(Enum):
    red = 4  # 4 is the bit representation
    red_yellow = 6
    green = 1
    yellow = 2

print(TrafficLights.yellow)
print(TrafficLights(2))
print(repr(TrafficLights.yellow))

# Looking at object attributes
print(dir(TrafficLights.yellow))

# Accessing value by name
print(TrafficLights.yellow.value)

for light in TrafficLights:
    print(light)

Note that the traffic lights have a particular bit representation, and cannot take any other values. Also, the class is iterable and the items can be accessed by name or by value, which is not possible with regular attributes.

Bottom line, enum is not an essential module, but is nice to have. It can be useful for specific use cases, where a limited set of enumerated objects is required.

Community
  • 1
  • 1
sammy
  • 857
  • 5
  • 13
  • The example you have given is just like what I have written in above code, as you said we can access items by name or value, I have tried by the name and only got in return `Days.Mon` So I am not seeing any point why to use it? If it were delivering the name("Mon") it would be of use. We cannot get value through name so what is the meaning of being a constant. – El_Dorado Dec 17 '19 at 11:32
  • 1
    Extended my answer for details. Constant means that you have a fixed pre-defined set of names and values that represent a particular type of thing, like a rainbow or traffic lights. – sammy Dec 17 '19 at 11:36
  • 1
    Got it, boss. As I understand, Enum is simply a class of a specific set of an object having constant variables of that set which we cannot change. And by the calling of that class name, we can use it simply without any issues and don't have to remember much. Example: Class Solar_system(Enum): Mercury = 1 . Pluto =9 – El_Dorado Dec 17 '19 at 12:24
  • @El_Dorado, yes that's right. It's convenient because when you work with huge amounts of code an Enum allows you to know exactly what you are dealing with. And that's important in cognitive terms, it eases you workload of thinking. Plus, all the additional specialized functionality Enum provides in certain use cases, that otherwise you would have to implement yourself. I think it also makes makes code syntax better. The Enum type does take a bit of learning, it's nuanced. – bad_coder Dec 17 '19 at 12:33
  • 1
    @bad_coder Finally, the cleared enum concept in python. Now will have to just wait for the opportunities where I will learn more about it and it's other functionalities. **Just out of curiosity is enum a class in Python?** – El_Dorado Dec 17 '19 at 12:40
  • 1
    Well, if you `import enum` and print the module object (`print(enum)`), you will see the file path to the module (the file `enum.py`). You can inspect the module source code and study the implementation. E.g., you will see a line like `class Enum(metaclass=EnumMeta):`. This means that `enum.Enum` is a class and at the same time an instance of the metaclass `enum.EnumMeta`. Metaclasses are classes that customize the creation behavior of classes. – sammy Dec 17 '19 at 12:47
  • @El_Dorado The enum module (lower-case) from which you import, defines four enumeration classes. Enum, IntEnum, Flag, IntFlag (upper-case). Enjoy the enum, for me it adds fun to programming (besides its inherent quality). You have one final dilemma, 3 good answers so far, and you can only accept one... – bad_coder Dec 17 '19 at 12:51
  • 1
    @bad_coder yeah right. I think I will go with Sammy's answer. Thank you for your guidance. I am very grateful to you. – El_Dorado Dec 17 '19 at 13:08
5

From the documentation

An enumeration is a set of symbolic names (members) bound to unique, constant values

The keywords are bound to unique and constant values.

Say you have

>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3

and

>>> class ColorClass():
...     RED = 1
...     GREEN = 2
...     BLUE = 3

You are allowed to do this

>>> ColorClass.RED = 3
>>>

But when you do

>>> Color.RED = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Programme\Python37\lib\enum.py", line 386, in __setattr__
    raise AttributeError('Cannot reassign members.')
AttributeError: Cannot reassign members.

you get

AttributeError: Cannot reassign members.

abhilb
  • 5,639
  • 2
  • 20
  • 26
  • okay. So if it is immutable and also we can't get value out from the `Color.RED`. Then I think this is better than enum. `mat, cat, bat = (1,2,34)` `print(mat)` `print(mat,cat,bat)` I am not seeing any good use or special use or any important part in python. – El_Dorado Dec 17 '19 at 11:29
  • The error example has a typo. The class variable of `ColorClass` class can be reassigned. The value of RED in the enum descendant class cannot: `Color.RED = 3` gives the error while `ColorClass.RED` = 3 is valid. – Helder Daniel Aug 26 '22 at 11:16
4

When you do Days['Fri'] you are getting an Enum member. (A member, is both the name, and the value). So the following comparisons work:

print(Days['Fri'].name == "Fri")
print(Days['Fri'].value == "1312312")

In the following line, you can see the enum member itself, with its symbolic name. As the other answers highlight.

print(Days['Fri'])
print(Days.Fri)

I hope this addresses the questions at the end of your post, and your fundamental doubts, directly. Using your own code. (I suggest you use the debugger instead of the prints should you get confused, because the debugger helps visualize the enum.)

Your question in the title: "differences between an enum and a regular class" has a broad answer. Let's say the enum type provides lots of special nuanced functionality, and being a part of the python standard library offers that functionality as the most of pythonic way of doing things. From the python docs for enum, with two examples:

diff comp flag

bad_coder
  • 11,289
  • 20
  • 44
  • 72