You have a good point (and as static typing proponent I should have thought
of that).

Maybe there is not actually a use case for passing an arbitrary default?
Then maybe overloading __contains__ (‘in’) might be better? The ergonomics
of that seem better for the dominant use case (“is this a valid value for
that enum?”).

On Mon, Mar 15, 2021 at 21:37 Matt Wozniski <godlyg...@gmail.com> wrote:

> I find the idea of having the constructor potentially return something
> other than an instance of the class to be very... off-putting. Maybe it's
> the best option, but my first impression of it isn't favorable, and I can't
> think of any similar case that exists in the stdlib today off the top of my
> head. It seems like we should be able to do better.
>
> If I might propose an alternative before this gets set in stone: what if
> `Enum` provided classmethods `from_value` and `from_name`, each with a
> `default=<sentinel>`, so that you could do:
>
> Color.from_value(1)  # returns Color.RED
> Color.from_value(-1)  # raises ValueError
> Color.from_value(-1, None)  # returns None
>
> Color.from_name("RED")  # returns Color.RED
> Color.from_name("BLURPLE")  # raises ValueError
> Color.from_name("BLURPLE", None)  # returns None
>
> That still allows each concept to be expressed in a single line, and
> remains explicit about whether the lookup is happening by name or by value.
> It allows spelling `default=None` as just `None`, as we desire. And instead
> of being a `__contains__` with unusual semantics coupled with a constructor
> with unusual semantics, it's a pair of class methods that each have fairly
> unsurprising semantics.
>
> ~Matt
>
> On Mon, Mar 15, 2021 at 3:55 PM Guido van Rossum <gu...@python.org> wrote:
>
>> +1
>>
>> On Mon, Mar 15, 2021 at 12:48 PM Ethan Furman <et...@stoneleaf.us> wrote:
>>
>>> On 3/15/21 11:27 AM, Guido van Rossum wrote:
>>> > On Mon, Mar 15, 2021 at 10:53 AM Ethan Furman wrote:
>>>
>>> >> 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'.)
>>>
>>> They could overlap if the Enum is a `str`-subclass -- although having
>>> the name of one member match the value of a different member seems odd.
>>>
>>> >> 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?
>>>
>>> I would enforce that both match, or raise.  Also not sure what the
>>> use-case would be.
>>>
>>> > 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
>>>
>>> Very good points.
>>>
>>> Everything considered, I think I like allowing `__contains__` to verify
>>> both names and values, adding `default=<sentinel>` to the constructor for
>>> the value-based "gimme an Enum or None" case, and recommending  `getattr`
>>> for the name-based "gimme an Enum or None" case.
>>>
>>> --
>>> ~Ethan~
>>> _______________________________________________
>>> 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/UQBSDZQJWBKMOVSUES7HEDJTYR76Y5N2/
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>>
>>
>> --
>> --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/ZK7KKABFNSFC4UY763262O2VIPZ5YDPQ/
>
>
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
> --
--Guido (mobile)
_______________________________________________
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/6NZB2GDVI5ZQJLYCJWGTIMC5TWI6P7HD/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to