On 04/02/2017 09:49 PM, Oren Ben-Kiki wrote:
The current behavior of `auto` is to pick a value which is one plus the previous value.
Starting with 1 if no previous value exists.
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.
Possibly.
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".
MyEnum.BAR exists, and works. It just happens to be the same as MyEnum.BAZ -- which did not exist when the value for BAR was chosen.
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.
Python code is executed top-down. First FOO, then BAR, then BAZ. It is not saved up and executed later in random order. Or, put another way, the value was appropriate when it was chosen -- it is not the fault of auto() that the user chose a conflicting value (hence why care should be taken).
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.
In other words, the currently existing values, because the future values don't exist yet.
I propose that: 1. The documentation will be more explicit about the way `auto` behaves in the presence of following values.
I can do that.
2. The default behavior of `auto` would avoid generating a conflict with following values.
I could do that, but I'm not convinced it's necessary, plus there would be backwards compatibility constraints at this point.
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.
This might work for you (untested): def _generate_next_value_(name, start, count, previous_values): if not count: return start or 1 previous_values.sort() last_value = previous_values[-1] if last_value < 1000: return 1001 else: return last_value + 1
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).
No, I'm not interested in doing that. I currently have that kind of code in aenum[1] for 2.7 compatibility, and it's a nightmare to maintain.
-- ~Ethan~ [1] https://pypi.python.org/pypi/aenum Advanced Enumerations NamedConstants NamedTuple (metaclass based namedtuple -- no code eval) plus a bunch of other goodies -- https://mail.python.org/mailman/listinfo/python-list