On Mon, Mar 15, 2021 at 10:53 AM Ethan Furman <et...@stoneleaf.us> wrote:

> On 3/12/21 5:28 PM, Guido van Rossum wrote:
> > On Fri, Mar 12, 2021 at 1:52 PM Ethan Furman wrote:
>
> >> A question that comes up quite a bit on Stackoverflow is how to test
> >> to see if a value will result in an Enum member, preferably without
> >> having to go through the whole try/except machinery.
> >>
> >> A couple versions ago one could use a containment check:
> >>
> >>     if 1 in Color:
> >>
> >> but than was removed as Enums are considered containers of members,
> >> not containers of the member values.
> >
> > Maybe you were a bit too quick in deleting it. Was there a serious
> > bug that led to the removal? Could it be restored?
>
> Part of the reason is that there are really two ways to identify an
> enum -- by name, and by value -- which should `__contains__` work with?
>

The two sets don't overlap, so we could allow both. (Funny interpretations
of `__contains__` are not unusual, e.g. substring checks are spelled 'abc'
in 'fooabcbar'.)


> >> At this point I see three options:
> >>
> >> 1) add a `get(value, default=None)` to EnumMeta (similar to
> `dict.get()`
> >
> > But the way to convert a raw value to an enum value is Color(1), not
> > Color[1], so Color.get(1) seems inconsistent.
>
> Very good point.
>
> > Maybe you can just change the constructor so you can spell this as
> > Color(1, default=None) (and then check whether that's None)?
>
> An interesting idea.
>
> >> 2) add a recipe to the docs
> >
> > But what would the recipe say? Apparently you're looking for a one-liner,
> > since you reject the try/except solution.
>
> The recipe would be for a method that could be added to an Enum, such as:
>
>      @classmethod
>      def get_by_value(cls, value, default=None):
>          for member in cls:
>              if member.value == value:
>                  return member
>          return default
>

But that's a non-solution -- people can figure out how to write such a
helper just fine (although probably using try/except) but they don't want
to -- they have *one* line where they want to do this check and so they're
going for a local solution -- probably the try/except.


> >> 3) do nothing
> >
> > Always a good option. :-)
>
> Yes, but not always a satisfying one.  :)
>
> >  Where's that StackOverflow item? How many upvotes does it have?
>
>
> 93 - How do I test if int value exists in Python Enum without using
> try/catch?
>      https://stackoverflow.com/q/43634618/208880
>
> 25 - How to test if an Enum member with a certain name exists?
>      https://stackoverflow.com/q/29795488/208880
>
>   3 - Validate value is in Python Enum values
>      https://stackoverflow.com/q/54126570/208880
>
>   2 - How to check if string exists in Enum of strings?
>      https://stackoverflow.com/q/63335753/208880
>
> I think I like your constructor change idea, with a small twist:
>
>      Color(value=<sentinel>, name=<sentinel>, default=<sentinal>)
>
> This would make it possible to search for an enum by value or by name, and
> also specify a default return value (raising an exception if the default is
> not set and a member cannot be found).
>

So specifically this would allow (hope my shorthand is clear):
```
Color['RED'] --> Color.RED or raises
Color(1) -> Color.RED or raises
Color(1, default=None) -> Color.RED or None
Color(name='RED', default=None) -> Color.RED or None
```
This seems superficially reasonable. I'm not sure what Color(value=1,
name='RED') would do -- insist that both value and name match? Would that
have a use case?

My remaining concern is that it's fairly verbose -- assuming we don't
really need the name argument, it would be attractive if we could write
Color(1, None) instead of Color(1, default=None).

Note that instead of Color(name='RED') we can already write this:
```
getattr(Color, 'RED') -> Color.RED or raises
getattr(Color, 'RED', None) -> Color.RED or None
```

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/CIXFX5SL5DX4ISZOWXJFFYVQK53FGQ27/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to