{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/add-attributes-to-enum-members/",
  "description": "Master adding multiple attributes to Python enum members using __new__ method. Avoid hardcoded indexes and create more maintainable enums.",
  "path": "/python/add-attributes-to-enum-members/",
  "publishedAt": "2022-02-17T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python"
  ],
  "textContent": "While grokking the source code of the [http.HTTPStatus] module, I came across this technique\nto add extra attributes to the values of enum members. Now, to understand what do I mean by\nadding attributes, let's consider the following example:\n\nHere, I've inherited from str to ensure that the values of the enum members are strings.\nThis class can be used as follows:\n\nRunning the script will print:\n\nWhile this works but it's evident that you can only assign a single value to an enum member.\nHow'd you rewrite this if you needed multiple values attached to a single enum member?\n\nSuppose, in the above case, along with the color title, you also need to save the hex codes\nand short descriptions of the colors. One way you can achieve this is via the assignment of\nan immutable container as the value of an enum member:\n\nHere, I'm using a tuple to contain the title, hex code, and description of the Color\nmembers. This gets awkward whenever you'll need to access the individual elements inside the\ntuple. You'll have to use hardcoded indexes to access the elements of the tuple. This is how\nyou'll probably use it:\n\nIt prints:\n\nHardcoding indexes in such a manner is fragile and will break if you drop a new value in the\nmiddle of the tuple assigned to an enum member. Also, it's hard to reason through logic when\nyou've to keep the semantic meanings of the index positions in your working memory. A better\nthing to do is to rewrite the enum in a way that'll allow you to access different elements\nof the member values by their attribute names. Let's do it:\n\nHere, I overrode the __new__ method of the class Color. Method __new__ is a special\nclass method that you don't need to decorate with the @classmethod decorator. It gets\nexecuted during the creation of the Color object; before the __init__ method. Other than\nthe first argument cls, you can define the __new__ method with any number of arbitrarily\nnamed arguments.\n\nIn this case, the value of each member of Color will have three elements - title,\nhex_code, and description. So, I defined the __new__ method to accept those arguments.\nIn the following line, the str class was initialized via obj = str.__new__(cls, title)\nand then title was assigned to the newly created string object via obj._value_=title.\nThis line is crucial; without it, the enum won't operate at all. This assignment makes sure\nthat the Enum.member.value will return a string value.\n\nIn the next two lines, hex_code and description were attached to the member values via\nthe obj.hex_code=hexcode and obj.description=description statements respectively.\n\nNow, you'll be able to use this enum without any hardcoded shenanigans:\n\nThis will print:\n\n\n\n\n[http.HTTPStatus]:\n    https://github.com/python/cpython/blob/6f1efd19a70839d480e4b1fcd9fecd3a8725824b/Lib/http/__init__.py#L6",
  "title": "Add extra attributes to enum members in Python"
}