3

I just started using Python for server-side programming (coming from TypeScript) and the verbosity of typing .value for an Enum is making me consider not using it at all.

In TypeScript the value of an Enum is retrieved like so..

enum CompassDirection {
  North = "North",
}

// I do not have to ask for the value
const isEqual = CompassDirection.North === "North" ? true : false

console.log(isEqual) // returns true 

But in Python I believe the only way to retrieve the value is using .value like so..

from enum import Enum

class CompassDirection(Enum):
    NORTH = 'NORTH'

isEqual = CompassDirection.NORTH == 'NORTH'
print(isEqual) // false

isEqual = CompassDirection.NORTH.value == 'NORTH'
print(isEqual) // true

My purpose of using Enum was for inference and so I wouldn't have to repeatedly type strings such as "NORTH" all in my code.

If I made a function I would have to call it everywhere as well - e.g.


def get_enum_value(enum): 
   return enum.value

# Calling this every time I want to use the enum.
get_enum_value(CompassDirection.NORTH)
get_enum_value(XEnum.Value)
get_enum_value(YEnum.Value)

Yet if I do not do this, this I'm repeatedly typing .value everywhere, which I'm finding counter-intuitive maybe because of my TypeScript bias.

Is there a way I can use Enum or a Dictionary achieve the inference that I want, keep my code as DRY as possible so I can avoiding typing my strings?

Note:

I don't mind making a few constants but I could see my imports getting lengthy for code-splitting / re-use.

Am I missing something? I'd like to understand this as soon as possible.

A Webb
  • 633
  • 1
  • 8
  • 16
  • 5
    If you simply don't inherit `Enum` at all, the class with string attributes will behave like you wanted. So is there really some feature from `Enum` that you _do_ need? – wim Oct 05 '21 at 21:46
  • 2
    I don't know why your question would get downvoted as long as it's a valid question that follows SO guidelines - which it seems to do. – rv.kvetch Oct 05 '21 at 21:58
  • The main value of `Enum` is that the *compiler* can catch a typo like `Nroth`. A string like `"Nroth"` will go undetected until your program misbehaves. `isEqual = CompassDirection.North == CompassDirection(x)`. You'll get an immediate error if `x` is not a valid direction. – chepner Oct 05 '21 at 21:59
  • One other option is to do a direct equality check in function. This is much more convenient. For example, `x = CompassDirection.NORTH; assert x is CompassDirection.NORTH # true`. Of course, this is assuming you don't really need to retrieve the value of the enum – rv.kvetch Oct 05 '21 at 22:01
  • For checking if Enum is *not* a specified member or name, you can similarly use an `is not` check. – rv.kvetch Oct 05 '21 at 22:05

1 Answers1

4

The immediate solution to your problem is to inherit from str as well as from Enum1:

class CompassDirection(str, Enum):
    NORTH = 'NORTH'

>>> print(CompassDirection.NORTH == 'NORTH')
True

The long-term solution is to realize that you should no longer be using strings, but the enum members, and using is:

somevar = CompassDirections.NORTH
#
# some intervening code
#
print(somevar is CompassDirections.NORTH)
# True

You should only have to deal with the string "NORTH" if getting input from a user, a configuration file, etc., and then you'll want to immediately convert to an Enum:

result = input('Enter direction')
result = CompassDirection(result.upper())

1 Python 3.11 will have a StrEnum type, which will ensure that the values are already of type str.


Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237