Behavior of auto in Enum and Flag.

Oren Ben-Kiki python-oren at ben-kiki.org
Mon Apr 3 00:49:50 EDT 2017


The current behavior of `auto` is to pick a value which is one plus the
previous value.

It would probably be better if `auto` instead picked a value that is not
used by any named member (either the minimal unused value, or the minimal
higher than the previous value). That is, in this simple case:

    class MyEnum(Enum):
        FOO = 1
        BAR = auto()
        BAZ = 2

It would be far better for BAR to get the value 3 rather than today's value
2.

In the less simple case of:

    class MyEnum(Enum):
        FOO = 2
        BAR = auto()
        BAZ = 3

Then BAR could be either 1 or 4 - IMO, 1 would be better, but 4 works as
well.

After all, `auto` is supposed to be used when:

"If the exact value is unimportant you may use auto instances and an
appropriate value will be chosen for you."

Choosing a value that conflicts with BAZ in above cases doesn't seem
"appropriate" for a value that is "unimportant".

The docs also state "Care must be taken if you mix auto with other values."
- fair enough. But:

First, why require "care" if the code can take care of the issue for us?

Second, the docs don't go into further detail about what exactly to avoid.
In particular, the docs do not state that the automatic value will only
take into account the previous values, and will ignore following values.

However, this restriction is baked into the current implementation:
It is not possible to just override `_generate_next_value_` to skip past
named values which were not seen yet, because the implementation only
passes it the list of previous values.

I propose that:

1. The documentation will be more explicit about the way `auto` behaves in
the presence of following values.

2. The default behavior of `auto` would avoid generating a conflict with
following values.

3. Whether `auto` chooses (A) the minimal unused value higher than the
previous value, or (B) the minimal overall unused value, or (C) some other
strategy, would depend on the specific implementation.

3. To allow for this, the implementation will include a
`_generate_auto_value_` which will take both the list of previous ("last")
values (including auto values) and also a second list of the following
("next") values (excluding auto values).

4. If the class implements `_generate_next_value_`, then
`_generate_auto_value_` will invoke `_generate_next_value_` with the
concatenation of both lists (following values first, preceding values
second), to maximize compatibility with existing code.

Thanks,

Oren Ben-Kiki


More information about the Python-list mailing list