[Python-Dev] Enum, Flag, __contains__, and False vs TypeError
Glenn Linderman
v+python at g.nevcal.com
Wed Apr 4 16:24:15 EDT 2018
On 4/4/2018 11:32 AM, Ethan Furman wrote:
> API question.
>
> Background:
> ----------
>
> When doing checks such as
>
> --> 3 in [4, 5, 6]
> --> 'test' in {'test':True, 'live':False}
>
> the result is True or False.
>
> When doing checks such as
>
> --> 3 in 'hello world'
> --> [4, 5, 6] in {'test':True, 'live':False}
>
> the result is a TypeError.
>
> The general rule seems to be that if it is impossible for the
> in-question object to be in the container object then a TypeError is
> raised, otherwise True or False is returned.
>
>
> Question 1:
> ----------
>
> (A) A standard Enum class is a container of Enum members. It cannot
> hold anything else. However, it has been returning False both in
> cases where the in-question object was an Enum of a different class (a
> Fruit in a Color, for example) and when the in-question object was not
> even an Enum ('apple' in Fruit, for example).
>
> (B) The waters get even more muddied when Fruit has a str mixin, so
> `Fruit.APPLE == 'apple' is True` -- in that case, should `'orange' in
> Fruit` return True, False, or raise TypeError?
>
>
> 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.
>
>
> My thoughts:
> -----------
>
> For question 1A (pure Enum): I'm thinking a TypeError should be
> raised when the in-question object is not an Enum member of any kind
> -- it simply is not possible for that object to ever be in an Enum,
> and is surely a bug.
>
> For question 1B (mixed Enum): if 1A is TypeError, then 1B should also
> be TypeError at least for non-mixin in-question types (so checking for
> 1 in StrEnum would be a TypeError), but I'm torn between TypeError and
> True/False for cases where the in-question type matches the mixin type
> ('apple' in StrEnum).... On the one hand, even though an Enum member
> might be equal to some other type, that other type will not have the
> Enum attributes, etc, and a True answer would lead one to believe you
> could access `.name` and `.value`, etc., while a False answer would
> lead one to believe there was no match even though equality tests
> pass; on the other hand, how strong is the "container" aspect of a
> mixed Enum? How often is the test `'apple' in Fruit` meant to
> discover if you have a Fruit member vs whether you have something that
> could be a Fruit member? Also, how important is it to be consistent
> with IntFlag, which I definitely think should return True/False for
> int checks?
>
> For question 2A (pure Flag): I'm comfortable sticking with a
> TypeError (assuming we switch to TypeError for 1A).
>
> For question 2B (int Flag): I think a TypeError if the in-question
> object is not an int is appropriate (assuming TypeError for 1A and
> 2A), but if it is an int, True/False seems the better path. My
> reasoning being that Flag and IntFlag are more similar to sets than
> lists, and IntFlag is specifically meant to work with ints, and a test
> of `2 in some_int_flags` is more concerned with a flag being set than
> with .name or .value attributes that may or may not exist on the
> in-question object.
>
> Any and all thoughts appreciated.
I think the "in" test should raise TypeError if tested against
_anything_ that is not an Enum member.
Why? I see a parallel between Enum and mappings.
x = {'test':True, 'live':False}
So it is True that 'test' in x and 'live' in x and False that True
in x and False in x.
It is False that 'foo' in x and 3 in x
It is TypeError that [4,5,6] in x, or {'foo': 'bar'} in x.
Note that it is False that (4,5,6) in x which is a little surprising
given the above two, but not when you realize the differences between
this and the above two.
So with mappings, you can have any hashable type as a key: with Enum,
you can only have Enum members as keys.
So I have no idea why you would want to return False, rather than
TypeError, other than (1) the distinction probably doesn't matter to
most people (2) backward compatibility.
I would find 2 in some_int_flags being True surprising.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180404/a2fff4e8/attachment.html>
More information about the Python-Dev
mailing list