5

Currently, I have an enum that represents a name/number mapping. Each EventType, however, also has additional "related properties" (e.g. a status code, and a message type).

class EventType(Enum):
  CANCELLED = 0
  ONTIME = 1
  DELAYED = 2

  def get_status(self):
    if self == EventType.CANCELLED:
        return "statuscode1"
    elif self == EventType.DELAYED:
        return "statuscode2"
    else:
        return "statuscode3"

  def get_message_type(self):
    if self == EventType.CANCELLED:
        return "messagetype1"
    elif self == EventType.DELAYED:
        return "messagetype2"
    else:
        return "messagetype3"

Instead of creating the methods above and tons of if chains checking against self, is there a cleaner way of refactoring to return the status codes and message types? It's almost as if CANCELLED = (0, statuscode1, messagetype1).. How can I represent this concept in an enum? Is an enum even the correct way to do this?

3
  • How is it a duplicate question? I already have code that represents an enum in the OP... Commented Oct 11, 2018 at 17:37
  • I think it is duplicate because if you see some of the top answers of that question, you can find ways to implement enum in python. Commented Oct 11, 2018 at 17:51
  • @MrAlihoseiny: The OP is not asking how to implement an enum type, but how to use the existing Enum type. Commented Oct 11, 2018 at 18:41

3 Answers 3

5

If you want the value of the Enum member to be 0, 1, or 2, then you will need to either override __new__, or use aenum.

Using the aenum library1:

from aenum import MultiValueEnum

class EventType(MultiValueEnum):
    _init_ = 'value status message'
    CANCELLED = 0, 'status1', 'message1'
    ONTIME = 1, 'status2', 'message2'
    DELAYED = 2, 'status3', 'message3'

and in use:

>>> print(EventType.ONTIME)
EventType.ONTIME
>>> print(EventType.ONTIME.value)
1
>>> print(EventType.ONTIME.status)
status2
>>> print(EventType.ONTIME.message)
message2

See this answer for an example of how to do this with the stdlib Enum (which uses the overriding __new__ technique).


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

Sign up to request clarification or add additional context in comments.

1 Comment

Ended up going with this approach. The other approach is nice and clean as well but this approach seemed a bit easier. Thanks!
2

In Python 3.4, there is a new Enum data type, which you can use as:

class EventType(Enum):

    def __init__(self, id, code, message):
        self.id = id
        self.code = code
        self.message = message

    CANCELLED = 1, 'code1', 'message1'
    ONTIME = 2, 'code2', 'message2'
    DELAYED = 3, 'code3', 'message3'

To use, simply:

EventType.CANCELLED.code # returns 'message1'

If it's just the use case you described, you can also use named tuple if you want:

from collections import namedtuple

    Event = namedtuple('event', ['id', 'code', 'message'])
    
    class EventType:
        CANCELLED = Event(1, 'code1', 'message1')
        ONTIME = Event(2, 'code2', 'message2')
        DELAYED = Event(3, 'code3', 'message3')

To use this one:

EventType.CANCELLED # return event(id=1, code='code1', message='message1')
EventType.CANCELLED.message # return message1

1 Comment

Good use of __init__. If the OP needs the values to be 0, 1, and 2, though, you should override __new__ instead. See my other answere here for an example.
1

You can use a tuple as the value of your Enum objects, and include the status and message strings together with the integer code. Then you can add methods (or property descriptors) to fetch individual pieces of the tuple via the value attribute:

class EventType(Enum):
   CANCELLED = 0, "status1", "message1"
   ONTIME = 1, "status2", "message2"
   DELAYED = 2, "status3", "message3"

   @property
   def code(self):
       return self.value[0]

   @property
   def status(self):
       return self.value[1]

   @property
   def message(self):
       return self.value[2]

print(EventType.CANCELLED.message) # prints "message3"

2 Comments

Neat! This method does leave member.value as the tuple instead of the int, though.
I'm going to try this method, as well as the aenum method answer above. Thank you both!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.