[Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library
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