Как получить доступ к значению Enum напрямую как атрибут класса? - PullRequest
0 голосов
/ 01 марта 2019

Я учусь использовать Enum классы в Python и обнаружил, что всякий раз, когда мне нужно получить доступ к фактическому значению перечисления, мне нужно добавить свойство .value:

from enum import Enum
class Pets(Enum):
    DOG = "Fido"
    CAT = "Kitty"

Pets.DOG # yields Pets.DOG
Pets.DOG.value # yields Fido

В качестве упражнения я пытаюсь настроить свой класс Enum так, чтобы мне не нужно было постоянно обращаться к этому свойству value. Мое желаемое поведение заключается в том, что когда я звоню Pets.DOG, я получаю Fido в качестве значения.

Я пытаюсь реализовать это с помощью __getattr_(cls, item):

class Pets(Enum):

    def __getattr__(self, item):
        print(f"__getattr__ called with {item}")
        return getattr(self, item).value

    DOG = "Fido"
    CAT = "Kitty"


if __name__ == "__main__":

    pets = Pets()
    pets.DOG

Однако я получаю RecursionError: maximum recursion depth exceeded while calling a Python object, а item - это строковое значение _value_.Я не совсем понимаю, почему такое поведение происходит - это встроенное поведение Python, или потому что я использую специальный класс Enum?

Я посмотрел на подобный пост SO, ноРешения были использовать другой модуль (inspect) или получить доступ к __dict__ или dir() и проанализировать его самостоятельно с помощью комбинации условных выражений или регулярных выражений.Есть ли лучший способ получить доступ к значению Enum?

1 Ответ

0 голосов
/ 01 марта 2019

Не используйте класс enum, если вы хотите отобразить атрибуты в строки.Весь пункт модуля enum предназначен для создания набора одноэлементных объектов, которые представляют перечисление, а не строки.Из документации модуля:

Перечисление - это набор символических имен (членов), привязанных к уникальным постоянным значениям .В пределах перечисления члены могут сравниваться по тождеству , а само перечисление может повторяться.)

выделение жирным шрифтом. Строки не являютсяуникальные постоянные значения (я могу создать больше "Fido" строк по желанию) и не предназначены для сравнения по тождеству (хотя иногда для подмножества строк можно ).

Просто определите свой собственный класс с атрибутами, которые являются строками, напрямую:

class Pets:
    DOG = "Fido"
    CAT = "Kitty"

Ваша бесконечная ошибка рекурсии вызвана недопониманием с вашей стороны относительно того, для чего используется этот метод.Подобно всем специальным методам , object.attr ищет __getattr__ для типа объекта , что означает здесь, что ваш метод применяется к экземплярам вашего Enum подклассаатрибуты DOG и CAT здесь, а не к самому классу, и мешают метаклассу EnumMeta, пытающемуся проверить атрибут _value_, который обрабатывается вашим методом __getattr__ с использованием selfтолько что созданный экземпляр Pets.DOG и item установлены в '_value_', который затем вызывает getattr(Pets.DOG, '_value_'), что вызывает __getattr__ и т. д.

Для вашего подхода к работе вам потребуетсядля подкласса EnumMeta и реализации __getattribute__ на этом подклассе (__getattr__ когда-либо вызывается только для отсутствующих атрибутов).Однако учтите, что __getattribute__ используется для доступа к атрибуту all , поэтому вам необходимо сначала проверить наличие экземпляров текущего класса:

class EnumDirectValueMeta(EnumMeta):
    def __getattribute__(cls, name):
        value = super().__getattribute__(name)
        if isinstance(value, cls):
            value = value.value
        return value

class Pets(Enum, metaclass=EnumDirectValueMeta):
    DOG = "Fido"
    CAT = "Kitty"

в этот моментPets.DOG производит 'Fido'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...