This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Allow reverse lookup (value-to-member) for Enum sublcasses decorated with @enum.unique
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: Nosy List: barry, eli.bendersky, ethan.furman, mmuddasani, serhiy.storchaka
Priority: normal Keywords:

Created on 2015-03-23 15:04 by mmuddasani, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (3)
msg239038 - (view) Author: Mohith (mmuddasani) Date: 2015-03-23 15:04
Addendum to issue 18042.

I've had a use case where I wanted to allow reverse lookups (i.e. value-to-member lookup) for my enum.Enum that was decorated via @enum.unique. In such a case, I would add my own class method that performs the logic. E.g. an unoptimized copy-and-paste-able example for use via python3 interactive shell:


import datetime
import enum

@enum.unique
class DayOfWeek(enum.Enum):
  SUNDAY = 0  # Sunday is '0' according to strftime('%w')
  MONDAY = 1
  TUESDAY = 2
  WEDNESDAY = 3
  THURSDAY = 4
  FRIDAY = 5
  SATURDAY = 6  # Saturday is '6' according to strftime('%w')
  @classmethod
  def reverse_lookup(cls, value):
    for _, member in cls.__members__.items():
      if member.value == value:
        return member
    raise LookupError

today_value = int(datetime.date.today().strftime('%w'))
today = DayOfWeek.reverse_lookup(today_value)
print('Today is', today.name.title())


---

(Aside: it seems like an optimized version that uses a cached lookup dictionary is inconvenient to implement in that it involves storing the cache in a global variable or a closure or a descriptor attribute or etc. [unless there's a simple recommended approach of which I am just unaware].)

I think use cases for reverse lookup would not be uncommon. For example, an IntEnum subclass decorated via @enum.unique is a great candidate (as is any simple hashable/equatable value type). I am unsure of the proper interface, but I am thinking that passing a boolean argument to enum.unique should enable the usage of a special __lookup__ metaclass property for optimized reverse lookups. I am thinking a possible (untested) enhancement to enum.unique along the lines of:


class EnumMeta(type):

  ...

  _reverse_lookup_ = None

  @property
  def __lookup__(cls):
    if cls._reverse_lookup_ is None:
      raise AttributeError('Reverse lookup unsupported.')
    return MappingProxyType(cls._reverse_lookup_)


def unique(enumeration, reverse_lookup=False):
    ...
    reverse_lookup = {} if reverse_lookup else None
    for name, member in enumeration.__members__.items():
      ...
      if reverse_lookup is not None:
        reverse_lookup[member.value] = member
    ...
    if reverse_lookup is not None:
      enumeration._reverse_lookup_ = reverse_lookup
    return enumeration
msg239039 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-03-23 15:08
Use DayOfWeek(today_value).
msg239040 - (view) Author: Mohith (mmuddasani) Date: 2015-03-23 15:24
Doh! That works. And it was in the documentation too. Silly me.

Apologies for opening an issue, and thanks for showing me the way!
History
Date User Action Args
2022-04-11 14:58:14adminsetgithub: 67939
2015-03-23 15:25:20ezio.melottisetstage: resolved
2015-03-23 15:24:14mmuddasanisetstatus: open -> closed
resolution: works for me
messages: + msg239040
2015-03-23 15:08:54serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg239039
2015-03-23 15:04:15mmuddasanicreate