Как я могу переопределить поведение по умолчанию для `list(MyEnum)`?

У меня есть пользовательские enum, MyEnum, в которых некоторые элементы имеют разные имена, но одинаковое значение.

from enum import Enum

class MyEnum(Enum):
    A = 1
    B = 2
    C = 3
    D = 1  # Same value as A

Следовательно, list(MyEnum) возвращает только имена некоторых членов (первое имя для каждого значения):

>>>list(MyEnum)
[<MyEnum.A: 1>, <MyEnum.B: 2>, <MyEnum.C: 3>]

Судя по всему, list(MyEnum.__members__) возвращает все имена:

>>>list(MyEnum.__members__)
['A', 'B', 'C', 'D']

Однако, если я попытаюсь переопределить метод __iter__() для моего перечисления, переопределение, похоже, не удастся:

class MyEnum(Enum):
    A = 1
    B = 2
    C = 3
    D = 1  # Same value as A

    @classmethod # an attempt to override list(MyEnum) that doesn't change anything  
    def __iter__(cls):
        return iter(list(cls.__members__)) 

Судя по всему, list(MyEnum) никогда не попадает в обычай __iter__() (на что указывает, скажем, добавление print() перед возвращением в наш кастом __iter__()).

Почему это?

Как я могу переопределить поведение list(MyEnum) по умолчанию, чтобы получить все разные имена?

🤔 А знаете ли вы, что...
Синтаксис Python известен своей простотой и читаемостью.


3
76
1

Ответ:

Решено

Метод класса — это не то же самое, что метод экземпляра метакласса, которым является __iter__ для Enum. Вам необходимо определить новый метакласс, который вы можете использовать для определения нового подкласса Enum, который делает то, что вы ищете.

Предостережение: я не утверждаю, что замена текущего поведения EnumType.__iter__ вашим предложением будет совместима с текущей семантикой Enum, но это сделает ваше определение доступным.

from enum import EnumType, Enum

class MyEnumType(EnumType):
    def __iter__(self):
        # Must return an Iterator, something with a __next__ method,
        # not an Iterable.
        return iter(list(self.__members__))

class MyEnumBase(Enum, metaclass=MyEnumType):
    pass

class MyEnum(MyEnumBase):
    A = 1
    B = 2
    C = 3
    D = 1

assert list(MyEnum) == ['A', 'B', 'C', 'D']