[Python-Dev] AutoNumber Enum

Ethan Furman ethan at stoneleaf.us
Wed Jun 29 15:23:32 EDT 2016


On 06/29/2016 12:11 PM, Guido van Rossum wrote:

> And how would you implement that without support from the compiler?
> Does it use a hook that catches the NameError?

It's built into the _EnumDict class dictionary used during class creation.

Current (edited) code from the aenum package that implements this:

class _EnumDict(dict):
     """Track enum member order and ensure member names are not reused.

     EnumMeta will use the names found in self._member_names as the
     enumeration member names.
     """
     def __init__(self, locked=True, start=1, multivalue=False):
         super(_EnumDict, self).__init__()
         # list of enum members
         self._member_names = []
         # starting value for AutoNumber
         self._value = start - 1
         # when the magic turns off
         self._locked = locked
         ...

     def __getitem__(self, key):
         if (
                 self._locked
                 or key in self
                 or _is_sunder(key)
                 or _is_dunder(key)
                 ):
             return super(_EnumDict, self).__getitem__(key)
         try:
             # try to generate the next value
             value = self._value + 1
             self.__setitem__(key, value)
             return value
         except:
             # couldn't work the magic, report error
             raise KeyError('%s not found' % key)

     def __setitem__(self, key, value):
         """Changes anything not sundured, dundered, nor a descriptor.
         Single underscore (sunder) names are reserved.
         """
         if _is_sunder(key):
             raise ValueError('_names_ are reserved for future Enum use')
         elif _is_dunder(key):
             if key == '__order__':
                 key = '_order_'
             if _is_descriptor(value):
                 self._locked = True
         elif key in self._member_names:
             # descriptor overwriting an enum?
             raise TypeError('Attempted to reuse name: %r' % key)
         elif not _is_descriptor(value):
             if key in self:
                 # enum overwriting a descriptor?
                 raise TypeError('%s already defined as: %r' % ...
             self._member_names.append(key)
             if not self._locked:
                 if isinstance(value, int):
                     self._value = value
                 else:
                     count = self._value + 1
                     self._value = count
                     value = count, value
         else:
             # not a new member, turn off the autoassign magic
             self._locked = True
         super(_EnumDict, self).__setitem__(key, value)

Disclaimer:  some errors may have crept in as I deleted unrelated 
content.  For the full code check out the _EnumDict class in the aenum 
package.

--
~Ethan~


More information about the Python-Dev mailing list