[Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library

Barry Warsaw barry at python.org
Sat Apr 20 21:18:08 CEST 2013


On Apr 13, 2013, at 11:31 AM, Serhiy Storchaka wrote:

>On 12.04.13 15:55, Eli Bendersky wrote:
>> The enumeration value names are available through the class members::
>>
>>      >>> for member in Colors.__members__:
>>      ...     print(member)
>>      red
>>      green
>>      blue
>
>This is unnecessary because enumerations are iterable. Colors.__members__ is
>equal to [v.name for v in Colors] and the latter looks more preferable,
>because it does not use the magic method.

__members__ was really a holdover from earlier versions.  I've removed this,
but I've added an __dir__().

>> The str and repr of the enumeration class also provides useful information::
>>
>>      >>> print(Colors)
>>      <Colors {red: 1, green: 2, blue: 3}>
>>      >>> print(repr(Colors))
>>      <Colors {red: 1, green: 2, blue: 3}>
>
>Does the enumeration's repr() use str() or repr() for the enumeration values?

No, enumeration values have different reprs and strs.

>And same question for the enumeration's str().

Enumerations share a repr and str (well, technically, Enums don't define a
__str__()).

>> To programmatically access enumeration values, use ``getattr``::
>>
>>      >>> getattr(Colors, 'red')
>>      <EnumValue: Colors.red [value=1]>
>
>How to get the enumeration value by its value?

Use getitem syntax:

    >>> from flufl.enum import Enum
    >>> A = Enum('A', 'a b c')
    >>> A[2]
    <EnumValue: A.b [value=2]>

>> Ordered comparisons between enumeration values are *not* supported.  Enums
>> are not integers (but see `IntEnum`_ below)::
>
>It's unexpected if values of the enumeration values have the natural
>order. And values of the enumeration values *should be* comparable
>("Iteration is defined as the sorted order of the item values").

This is one reason why Enums are not comparable except by equality.  While I
think it's not a good idea to mix the types of Enum item values, it *is*
possible, and I don't think we should add strict checks to enforce this for
the base Enum.  Thus we cannot guarantee that <, >, <=, or >= will not throw a
TypeError.

IntEnums do define these because they can be guaranteed to succeed, since
their enumeration item values are guaranteed to be integers.

>There is some ambiguity in the term "enumeration values". On the one hand,
>it's the singleton instances of the enumeration class (Colors.red,
>Colors.gree, Colors.blue), and on the other hand it is their values (1, 2,
>3).

I've just made sure that the flufl.enum using.rst document is consistent here.
The terms I'm using are "enumeration item" to define things like Colors.red
and "enumeration item value" (or sometimes just "enumeration value") to define
the value of the enumeration item, e.g. 2, and it's available on the .value
attribute of the item.  "Enumeration item name" is essentially the attribute
name, and is available on the .name attribute of the item.

>> But if the value *is* important,  enumerations can have arbitrary values.
>
>Should enumeration values be hashable?
>
>At least they should be comparable ("Iteration is defined as the sorted order
>of the item values").

Given my previous responses, these questions should be already answered.

>> ``IntEnum`` values behave like integers in other ways you'd expect::
>>
>>      >>> int(Shape.circle)
>>      1
>>      >>> ['a', 'b', 'c'][Shape.circle]
>>      'b'
>>      >>> [i for i in range(Shape.square)]
>>      [0, 1]
>
>What is ``isinstance(Shape.circle, int)``? Does PyLong_Check() return true
>for ``IntEnum`` values?

True.  Yes, because IntEnumValues inherit from int.

>Why the enumeration starts from 1? It is not consistent with namedtuple, in
>which indices are zero-based, and I believe that in most practical cases the
>enumeration integer values are zero-based.

There are several reasons:

* It's been that way since day 1 <wink> of the package
* Zero is special in a way; it's the only false integer value
* This is very easy to override
* If you're using the auto-numbering convenience API, then you don't care
  about the values anyway

>The Python standard library has many places where named integer constants
>used as bitmasks (i.e. os.O_CREAT | os.O_WRONLY | os.O_TRUNC, select.POLLIN |
>select.POLLPRI, re.IGNORECASE | re.ASCII). The proposed PEP is not applicable
>to these cases. Whether it is planned expansion of Enum or additional EnumSet
>class to aid in these cases?

IntEnums work fine for these cases, but it's true that the result of a logical
operation is an int and not a subclass with a nice repr.  Contributions are
welcome.

-Barry


More information about the Python-Dev mailing list