This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Enum: add "name" and "value" keywords to call syntax
Type: enhancement Stage:
Components: Versions: Python 3.11
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: ethan.furman Nosy List: aekoch, ethan.furman
Priority: normal Keywords:

Created on 2021-10-14 19:11 by aekoch, last changed 2022-04-11 14:59 by admin.

Messages (4)
msg403936 - (view) Author: Aaron Koch (aekoch) Date: 2021-10-14 19:11
Documentation: https://docs.python.org/3/library/enum.html#creating-an-enum

Current behavior:

SomeEnum[name] is used to construct an enum by name
SomeEnum(value) is used to construct an enum by value

Problem:

As a user of enums, it is difficult to remember the mapping between parenthesis/square brackets and construct from name/construct from value.

Suggestion: Add two class methods to Enum

@classmethod
def from_name(cls, name):
    return cls[name]

@classmethod
def from_value(cls, value):
    return cls(value)


Benefits:

This is an additive change only, it doesn't change any behavior of the Enum class, so there are no backwards compatibility issues.  Adding these aliases to the Enum class would allow readers and writers of enums to interact with them more fluently and with less trips to the documentation.  Using these aliases would make it easier to write the code you intended and to spot bugs that might arise from the incorrect use of from_name or from_value.
msg403949 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2021-10-14 21:16
The problem with adding methods is that those names are then unavailable for member names -- at least not without possible confusion.

Also, unlike the `name` and `value` instance attributes which do not hide class attributes (aka members) of the same name, `from_name` is a class method so we couldn't have both a `from_name()` class method and a `from_name` class member at the same time.

If those are issues you know wouldn't a problem for you, you can create your own base Enum class with those methods defined, and then inherit from them:

    class EasyEnum(Enum):
        @classmethod
        def from_name(cls, name):
            return cls[name]
        # etc

     class MyEnum(EasyEnum):
          RED = 1
          # etc.

On the other hand, if you want to use this with any enum, then you'll need to make your own helper functions:

    def from_name(enum, name):
        return enum[name]

    enum_member = from_name(MyEnum, 'RED')
msg403960 - (view) Author: Aaron Koch (aekoch) Date: 2021-10-14 23:11
Are there any other names that you would contemplate besides `from_name` and `from_value`?  My reading of your response indicates that you are fundamentally opposed to the addition of class methods, since they would limit the space of possible instance methods/members.  Is that a fair reading?

If it is not, would you be open to different method names?

Do you agree with the fundamental issue that is identified: that the parenthesis/square bracket construction is difficult to read and makes implementation mistakes more likely?  That it would be good to have some what to make it more explicit at both read and write time whether the enum is being constructed using the name or the value.

One alternative to the class methods I might propose is to use a keyword argument in the __init__ function.
SomeEnum(name="foo")
SomeEnum(value="bar")

This would also solve the stated problem, but I suspect that messing with the init function introduces more limitations to the class than the classmethod solution.
msg404017 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2021-10-15 13:53
> Are there any other names that you would contemplate besides `from_name` and
> `from_value`?

No.

> My reading of your response indicates that you are fundamentally opposed to
> the addition of class methods, since they would limit the space of possible
> instance methods/members.  Is that a fair reading?

Yes.

Instance methods/attributes are not an issue, though, as the instance namespace and the class namespace are distinct -- which is why we can have a `value` member even though each member has a `value` attribute.

The issue is that class methods/attributes and members (which look like attributes) all live in the class namespace, so we cannot have both a `from_value` member and a `from_value` class method in the class namespace.

> Do you agree with the fundamental issue that is identified: that the
> parenthesis/square bracket construction is difficult to read and makes
> implementation mistakes more likely?

Only partially.  Being able to easily tell the difference between round and square brackets is an important skill to have.  With enums, square brackets are akin to dictionary lookup, which uses (string) keys, and the keys of an enum are the member names; that leaves round brackets (parenthesis), which is call syntax, for value lookup.

Additionally, if the wrong syntax is used then an exception will be raised at that location, making it an easy  fix.

> One alternative to the class methods I might propose is to use a keyword
> argument in the __init__ function.
>
>    SomeEnum(name="foo")
>    SomeEnum(value="bar")
>
> This would also solve the stated problem, but I suspect that messing with the
> init function introduces more limitations to the class than the classmethod
> solution.

This idea has come up before.  I'll look into it.
History
Date User Action Args
2022-04-11 14:59:51adminsetgithub: 89636
2021-10-15 13:53:38ethan.furmansetmessages: + msg404017
title: Enum add "from_name" and "from_value" class methods -> Enum: add "name" and "value" keywords to call syntax
2021-10-14 23:11:58aekochsetmessages: + msg403960
2021-10-14 21:16:06ethan.furmansetmessages: + msg403949
2021-10-14 19:21:58ethan.furmansetassignee: ethan.furman

nosy: + ethan.furman
versions: + Python 3.11
2021-10-14 19:11:28aekochcreate