Перечисления Python: заменить `element` на` element.value` - PullRequest
2 голосов
/ 24 июня 2019

У меня есть простой Enum:

class E(Enum):
    A = 'a'
    B = 'b'

Для доступа к 'a' я должен набрать E.A.value. Однако value - единственное, что мне нужно от объекта Enum.

Как написать Enum, где 'a' может быть доступен только E.A?

Ответы [ 2 ]

2 голосов
/ 11 июля 2019

Использование int в качестве значения было только примером.На самом деле это должен быть пользовательский класс.

Если вы смешаете класс / тип с Enum, то простой доступ к самому члену даст вам подтип этого типа:

from enum import Enum

class MyClass:
    def __init__(self, color):
        self.color = color

class MyEnum(MyClass, Enum):
    first = 'red'
    second = 'green'
    third = 'blue'

и используется:

>>> MyEnum.first
<MyEnum.first: 'red'>

>>> MyEnum.first.color
'red'

>>> type(MyEnum.first)
<enum 'MyEnum'>

>>> isinstance(MyEnum.first, MyClass)
True

Раскрытие информации: я являюсь автором Python stdlib Enum, enum34 backport и расширенное перечисление (aenum) .

1 голос
/ 24 июня 2019

Я много осматривался и не смог найти хорошего решения этой проблемы, используя класс Enum, который вы пытаетесь использовать. Однако, если вы хотите отказаться от идеи использования Enum в качестве суперкласса, вы можете использовать это вместе:

class Demo:
    # something with a 'value' method in it
    def __init__(self, val):
        self.value = val

def custom_enum(cls):
    # class decorator to get __getattribute__() to work properly
    # this is necessary because __getattribute__() only exists as an instance method,
    #   and there seems to be no direct equivalent for class methods
    return cls()

@custom_enum
class E:
    # first, define our enumerated variables in a dict
    _enums = {
        'A': Demo('a'),
        'B': Demo('b'),
        'chicken': Demo('cluck')
    }

    # then, override __getattribute__() to first get the key from the dict, 
    #   and return the .value property of it
    def __getattribute__(self, key):
        # because of the decorator, we can't call self._enums or else we get a RecursionError
        # therefore, we need to implicitly subclass `object`, and then
        #   deliberately invoke object.__getattribute__ on self, to access _enums
        my_enums = object.__getattribute__(self, '_enums')
        return my_enums[key].value

На самом деле определить значения вашего перечислимого так же просто, как редактировать _enums dict. И как только вы это сделаете, все должно работать примерно так, как вы хотите:

>>> E.A
'a'
>>> E.B
'b'
>>> E.chicken
'cluck'

Отсюда вы можете изменить реализацию, если это необходимо (например, вернуть AttributeError вместо KeyError, например, или переопределить __setattr__(), чтобы сделать значения enum не устанавливаемыми, или что-то еще).

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