
# Feature or enhancement `len(Enum)` has no useful meaning and should therefore raise the appropriate error # Pitch I cannot figure out any scenario, in which len(Enum) should not raise. Enum is a type and as any other types, such as `len(list)` or `len(dict)`, and should not give any meaningful result on len. Thoughts?

On 2/04/23 6:36 pm, Benedict Verhegghe wrote:
An Enum is functionally a container with a limited set of constants. Why should it not be legitimate to ask for the number of constants in it?
But Enum itself isn't an enum, it's a constructor for enums. I think len() just happens to work on it as a side effect of the way enums are implemented. -- Greg

I believe that is the core question. In my use case it caused a bug because I accidentally typed "Enum" instead of "MyEnum" and the "len" worked, which is something I did not expect. However I do not know how prevalent this mistake is.

Enum is not a type, like the OP suggested: from enum import Enum class Color(Enum): WHITE = 1 type(Color) <class 'enum.EnumMeta'> type(Enum) <class 'enum.EnumMeta'> type(enum.EnumMeta) <class 'type'> Enum.__len__ <bound method EnumMeta.__len__ of <enum 'Enum'>> So to me it looks like Enum is just a generic, empty enum. The __len__ method is implemented in EnumMeta. Op 3/04/2023 om 00:18 schreef Greg Ewing:

On Mon, 3 Apr 2023 at 15:54, Benedict Verhegghe <bverheg@gmail.com> wrote:
Enum is not a type, like the OP suggested:
Well, it is:
isinstance(Enum, type) True
but it has a metaclass, meaning that the type of Enum is a subclass of type.
I mean, we wouldn't be subclassing it if it weren't a type. The __len__ method is implemented on the metaclass to allow all Enum subclasses to have lengths (ditto __iter__ to make them iterable), and as a consequence of that, Enum itself has all the attributes that it wants to give to its subclasses. ChrisA

Well, it's not an object of type 'type' like the list or dict mentioned by the OP, for which len() give a TypeError: object of type 'type' has no len() Any derived class of Enum will also return True for isinstance(..., type). Should the derived classes then neither have a meaningful result for len()? Enum and derived classes hold a container with a fixed set of values. It makes perfectly sense to ask for the number of possible values, even when there are none. Op 3/04/2023 om 08:53 schreef Chris Angelico:

On Mon, 3 Apr 2023 at 17:57, Benedict Verhegghe <bverheg@gmail.com> wrote:
I'm not sure what you mean here. Enum is of type EnumMeta, which is a subclass of type. That means that, according to the normal rules of type hierarchy, Enum is indeed a type. Types add functionality that the parent type (with some Exceptions), so it should be no surprise that EnumMeta can add a __len__ method that type itself didn't have.
Any derived class of Enum will also return True for isinstance(..., type).
Yes, that is correct. Any subclass of Enum will also be a type, and will have a length.
Yeah, and I'm of the opinion that it's not a problem for Enum to have zero possible values, but to have the concept of values. Although it also wouldn't be a problem if it didn't. ChrisA

Yes, that is correct. Any subclass of Enum will also be a type, and will have a length.
That is the correct and expected behavior, as described on https://docs.python.org/3/library/enum.html
Yeah, and I'm of the opinion that it's not a problem for Enum to have zero possible values, but to have the concept of values.
I encountered that Enum having a len hid a mistake on my part. If len(Enum) raised, my mistake would be immediately apparent, however at the end of the day, my mistake was easily found. I am using this issue to mostly try how to contribute to Python and I do not have strong opinion on this issue either way. IMHO len(Enum) should raise, but idk if it is worth potential downstream breakages.

Hi Richard, On Tue, 4 Apr 2023 at 12:49, Richard Hajek <richard.m.hajek@gmail.com> wrote:
I encountered that Enum having a len hid a mistake on my part. If len(Enum) raised, my mistake would be immediately apparent, however at the end of the day, my mistake was easily found.
Can any Python linting tools (such as pylint) detect a potential problem with the code? Thanks, James

Hi Here's a similar example $ python3
This is what happens without the typo.
Here's a link to the source for Counter.update: https://github.com/python/cpython/blob/3.11/Lib/collections/__init__.py#L658... -- Jonathan

mypy does not detect this as a problem because EnumMeta has a `.__len__` method https://github.com/python/typeshed/blob/60939b00afede13feeec3cee6f6dfe6eb2df... what would the type hints look like if len(Enum) failed but class Foo(Enum): pass len(Foo) succeeds?

On 4/1/23 07:45, Richard Hajek wrote:
Enums are not like any other type in a multitude of ways: `__len__`, `__contains__`, `__getitem__`, etc. Special-casing only `Enum`, `IntEnum`, `StrEnum`, and every other base enum (i.e. no members), would be like special-casing empty lists, empty dicts, empty tuples, etc. -- ~Ethan~

In addition to this, there's nothing wrong with defining additional behavior on class objects. They're just objects. The pattern of class objects acting as containers of registered instances is used in many places, and it makes perfect sense here IMO. On Tue, Apr 4, 2023, at 2:54 PM, Ethan Furman wrote:

On 2/04/23 6:36 pm, Benedict Verhegghe wrote:
An Enum is functionally a container with a limited set of constants. Why should it not be legitimate to ask for the number of constants in it?
But Enum itself isn't an enum, it's a constructor for enums. I think len() just happens to work on it as a side effect of the way enums are implemented. -- Greg

I believe that is the core question. In my use case it caused a bug because I accidentally typed "Enum" instead of "MyEnum" and the "len" worked, which is something I did not expect. However I do not know how prevalent this mistake is.

Enum is not a type, like the OP suggested: from enum import Enum class Color(Enum): WHITE = 1 type(Color) <class 'enum.EnumMeta'> type(Enum) <class 'enum.EnumMeta'> type(enum.EnumMeta) <class 'type'> Enum.__len__ <bound method EnumMeta.__len__ of <enum 'Enum'>> So to me it looks like Enum is just a generic, empty enum. The __len__ method is implemented in EnumMeta. Op 3/04/2023 om 00:18 schreef Greg Ewing:

On Mon, 3 Apr 2023 at 15:54, Benedict Verhegghe <bverheg@gmail.com> wrote:
Enum is not a type, like the OP suggested:
Well, it is:
isinstance(Enum, type) True
but it has a metaclass, meaning that the type of Enum is a subclass of type.
I mean, we wouldn't be subclassing it if it weren't a type. The __len__ method is implemented on the metaclass to allow all Enum subclasses to have lengths (ditto __iter__ to make them iterable), and as a consequence of that, Enum itself has all the attributes that it wants to give to its subclasses. ChrisA

Well, it's not an object of type 'type' like the list or dict mentioned by the OP, for which len() give a TypeError: object of type 'type' has no len() Any derived class of Enum will also return True for isinstance(..., type). Should the derived classes then neither have a meaningful result for len()? Enum and derived classes hold a container with a fixed set of values. It makes perfectly sense to ask for the number of possible values, even when there are none. Op 3/04/2023 om 08:53 schreef Chris Angelico:

On Mon, 3 Apr 2023 at 17:57, Benedict Verhegghe <bverheg@gmail.com> wrote:
I'm not sure what you mean here. Enum is of type EnumMeta, which is a subclass of type. That means that, according to the normal rules of type hierarchy, Enum is indeed a type. Types add functionality that the parent type (with some Exceptions), so it should be no surprise that EnumMeta can add a __len__ method that type itself didn't have.
Any derived class of Enum will also return True for isinstance(..., type).
Yes, that is correct. Any subclass of Enum will also be a type, and will have a length.
Yeah, and I'm of the opinion that it's not a problem for Enum to have zero possible values, but to have the concept of values. Although it also wouldn't be a problem if it didn't. ChrisA

Yes, that is correct. Any subclass of Enum will also be a type, and will have a length.
That is the correct and expected behavior, as described on https://docs.python.org/3/library/enum.html
Yeah, and I'm of the opinion that it's not a problem for Enum to have zero possible values, but to have the concept of values.
I encountered that Enum having a len hid a mistake on my part. If len(Enum) raised, my mistake would be immediately apparent, however at the end of the day, my mistake was easily found. I am using this issue to mostly try how to contribute to Python and I do not have strong opinion on this issue either way. IMHO len(Enum) should raise, but idk if it is worth potential downstream breakages.

Hi Richard, On Tue, 4 Apr 2023 at 12:49, Richard Hajek <richard.m.hajek@gmail.com> wrote:
I encountered that Enum having a len hid a mistake on my part. If len(Enum) raised, my mistake would be immediately apparent, however at the end of the day, my mistake was easily found.
Can any Python linting tools (such as pylint) detect a potential problem with the code? Thanks, James

Hi Here's a similar example $ python3
This is what happens without the typo.
Here's a link to the source for Counter.update: https://github.com/python/cpython/blob/3.11/Lib/collections/__init__.py#L658... -- Jonathan

mypy does not detect this as a problem because EnumMeta has a `.__len__` method https://github.com/python/typeshed/blob/60939b00afede13feeec3cee6f6dfe6eb2df... what would the type hints look like if len(Enum) failed but class Foo(Enum): pass len(Foo) succeeds?

On 4/1/23 07:45, Richard Hajek wrote:
Enums are not like any other type in a multitude of ways: `__len__`, `__contains__`, `__getitem__`, etc. Special-casing only `Enum`, `IntEnum`, `StrEnum`, and every other base enum (i.e. no members), would be like special-casing empty lists, empty dicts, empty tuples, etc. -- ~Ethan~

In addition to this, there's nothing wrong with defining additional behavior on class objects. They're just objects. The pattern of class objects acting as containers of registered instances is used in many places, and it makes perfect sense here IMO. On Tue, Apr 4, 2023, at 2:54 PM, Ethan Furman wrote:
participants (9)
-
Benedict Verhegghe
-
Chris Angelico
-
Ethan Furman
-
Greg Ewing
-
James Addison
-
Jonathan Fine
-
outthere@me.gregwerbin.com
-
Richard Hajek
-
Thomas Grainger