[Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library (original) (raw)

Ethan Furman ethan at stoneleaf.us
Fri Apr 26 07:07:37 CEST 2013


On 04/25/2013 07:13 PM, Nick Coghlan wrote:

On Fri, Apr 26, 2013 at 8:29 AM, Barry Warsaw <barry at python.org> wrote:

On Apr 25, 2013, at 03:19 PM, Guido van Rossum wrote:

Clearly this is a trick question. :-) A bit, yes. :) I was told when this was brought up previously (a week ago?) that it would be simple to make it truly the same class. It didn't sound simple to me, but I haven't seen any actual code yet. I'm the one who said I didn't see any obvious barriers to the merger, but I've realised there is one, and it's similar to one namedtuple struggles with: how to handle method definitions. [snip] With a merged design, it becomes really hard to give the instances custom behaviour, because the metaclass will somehow have to differentiate between namespace entries that are intended to be callables, and those which are intended to be instances of the enum. This is not an easy problem to solve.

I'm probably going to regret asking this, but what's difficult with the following?

8<----------------------------------------------------------------------------------------- class EnumDict(dict): """ automatically assigns the next _int for an enum """

 def __init__(yo):
     super().__init__()
     yo._allow_duplicates = False
     yo._value = 1
     yo._base = 1
     yo._enums = []
     yo._type = None # object means enum, anything else means all must be of that type

 def __setitem__(yo, key, new_value):
     """
     main purpose is to support auto-numbering of members
     """
     existing = yo.get(key)
     if type(existing) is attrs:  # attrs is a helper class
         raise TypeError('Attempted to reuse key: %s' % key)
     if not key[:2] == key[-2:] == '__':
         old_value = None
         if isinstance(new_value, attrs):
             old_value = new_value
             if new_value.integer is None:
                 new_value = yo._value
             else:
                 new_value = new_value.integer
                 if not isinstance(new_value, int):
                     raise TypeError(
                         "an enum integer must be an instance of type <int>, not %s"
                         % type(new_value)
                         )
         if not callable(new_value):  # this if-else is probably not final
             if (isinstance(new_value, int) and old_value is not None
             or yo._type in (object, )):
                 yo._check_duplicate_integer(new_value, key)
                 yo._value = new_value
                 yo._inc_integer()
                 yo._enums.append(key)
                 new_value = attrs(integer=new_value)
             elif yo._type is None: # random bunch of named constants
                 yo._check_duplicate_integer(new_value, key)
                 value = yo._value
                 yo._inc_integer()
                 yo._enums.append(key)
                 new_value = attrs(value=new_value, integer=value)
             elif isinstance(new_value, yo._type): # single type of named constants
                 if isinstance(yo._type, int):
                     value = new_value
                 else:
                     value = yo._value
                 yo._check_duplicate_integer(value, key)
                 yo._inc_integer()
                 yo._enums.append(key)
                 new_value = attrs(value=new_value, integer=value)


         if old_value is not None:
             new_value, old_value.integer = old_value, new_value.integer
     dict.__setitem__(yo, key, new_value)

 def _inc_integer(yo):
     if yo._base == 1:
         yo._value += 1
     else:
         if yo._value == 0:
             value = 1
         else:
             value = floor(log(yo._value, 2))
             value = 2 ** value
             value <<= 1
         yo._value = value

 def _check_duplicate_integer(yo, new_value, key):
     for name, value in yo.items():
         if not isinstance(value, attrs):
             continue
         if value.integer == new_value and name != key and not yo._allow_duplicates:
             raise TypeError('duplicate value for %s: %d' % (key, value))

8<-------------------------------------------------------------------------------------------

Basically, if the assigned value is not attrs or a literal of the same type as the enum, the metaclass ignores it.

-- Ethan



More information about the Python-Dev mailing list