[Python-Dev] Enum, Flag, __contains__, and False vs TypeError

Ethan Furman ethan at stoneleaf.us
Wed Apr 4 16:25:42 EDT 2018


On 04/04/2018 12:40 PM, Barry Warsaw wrote:
> On Apr 4, 2018, at 11:32, Ethan Furman wrote:

>> (A) A standard Enum class is a container of Enum members.  It cannot hold anything else...
>>
>> (B) The waters get even more muddied when Fruit has a str mixin, so `Fruit.APPLE == 'apple' is True`...
>
> Are you proposing to change current behavior, and if so, what’s your deprecation plan?

The first problem is to determine what the correct behavior should be -- if that turns out to be different than what is 
we can then decide the time frame for changing it.  ;)

> I’m not sure I feel that the purity is important enough to change how it
 > currently works, especially since you’ll have to be prepared to catch
 > exceptions rather than just handle the boolean value.

It's not so much about purity as about bugs not passing silently.  But whether or not it's a bug depends on how 
"containerish" an Enum class is (or is perceived to be).

> OTOH, since most of my
 > use cases are comparisons against explicit enum values, I’m not sure how often
 > people write code to check for enum values contained in the Enum (I do it in
 > one or two places where I’m deserializing the actual value object, e.g. from a
 > pickle).

I write a bunch of cli scripts for work, so I'm often comparing a string value with an Enum value.  As often as not, I 
don't need the member itself, just to know that the string I have can be converted to a valid Enum -- `if "quick" in 
Method`, for example -- but just converting to an Enum is undoubtedly the better course of action .

> (FWIW, I encourage individual comparisons use `is` rather than `==`.)

Which is great for pure Enums, not so much for mixed.

>> Question 2:
>> ----------
>>
>> (A) The new Flag type allows `in` tests on the members themselves; so, for example:
>>
>> --> SomeFlag.ONE in SomeFlag.One|SomeFlag.TWO
>> True
>>
>> The question, of course, is what to do when a non-Flag member is tested for:
>>
>> --> 'apple' in SomeFlag.ONE
>> # False or TypeError?
>>
>> --> 2 in SomeFlag.TWO
>> # True or TypeError?
>>
>> (B) And, of course, the same muddier question arises with IntFlag, where SomeFlag.TWO == 2 is True.
>
> Well, now I’m confused:
>
> Python 3.7.0b2+ (heads/3.7:f328caf4ca, Mar 26 2018, 19:57:33)
> [Clang 9.0.0 (clang-900.0.39.2)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
> --> from enum import IntFlag
> --> class Flag(IntFlag):
> ...   a = 1
> ...   b = 2
> ...   c = 4
> ...   d = 8
> ...
> --> 'foo' in (Flag.a|Flag.b)
> True

Already being tracked at https://bugs.python.org/issue33217, which is what got me thinking about this whole issue.  True 
is obviously wrong, but should the correct answer be False, or TypeError?

--
~Ethan~


More information about the Python-Dev mailing list