On 04/03/2017 01:53 AM, Oren Ben-Kiki wrote:
On Mon, Apr 3, 2017 at 11:03 AM, Ethan Furman wrote:

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).

This is not to say that there's no possible workaround for this - the code 
could pretty easily defer invocation of
_generate_next_macro_ until after the whole class was seen. It would still 
happen in order (since members are an ordered
dictionary these days).

Possible, yes.  Easy, no.

So it is a matter of conflicting values - what would be more "Pythonic": 
treating auto as executed immediately, or
avoiding conflicts between auto and explicit values.

Since most things execute immediately, that is the pattern I chose.

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

I can do that.

Barring changing the way auto works, that would be best ("explicit is better than 
implicit" and all that ;-)

As for backward compatibility, the docs are pretty clear about "use auto when you 
don't care about the value"... and
Enum is pretty new, so there's not _that_ much code that relies on "implementation 
specific" details.

Fair point.

*If* backward compatibility is an issue here, then the docs might as well specify 
"previous value plus 1, or 1 if this
is the first value" as the "standard" behavior, and be done.

Actually, (Int)Flag uses the next power of two (not already seen) -- so it isn't as easy 
as "last value + 1".

This has the advantage of being deterministic and explicit, so people would be 
justified in relying on it. It would
still have to be accompanied by saying "auto() can only consider previous values, 
not following ones".

Something to that effect sounds good.

    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


This assumes no following enum values have values > 1000 (or some predetermined 
constant), which doesn't work in my
particular case, or in the general case. But yes, this might solve the problem 
for some people.

General code isn't going to "do what I need" 100% of the time for 100% of the people. That's why I made the _generate_next_value_ method user over-ridable

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.

Understood. Another alternative would be to have something like 
_generate_next_value_ex_ with the additional argument
(similar to __reduce_ex__), which isn't ideal either.

It's a lot more work than just making another method.

Assuming you buy into my "necessity" claim, that is...

It this point I do not. If you can give us an example Enum and why it's necessary to be built like that I might be swayed -- although the odds are good that the change will go into aenum instead (it's already a mess with the 2.7 compatibility code...).

Thanks,

You're welcome.

--
~Ethan~

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to