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/