Подтвердить что ты не робот

Преобразование строки в Enum в Python

Интересно, какой правильный способ преобразования (десериализации) строки в класс Python Enum. Кажется, что getattr(YourEnumType, str) выполняет эту работу, но я не уверен, насколько она достаточно безопасна.

Чтобы быть более конкретным, я хотел бы преобразовать строку 'debug' в объект Enum следующим образом:

class BuildType(Enum):
    debug = 200
    release = 400
4b9b3361

Ответ 1

Эта функция уже встроена в Enum [1]:

>>> from enum import Enum
>>> class Build(Enum):
...   debug = 200
...   build = 400
... 
>>> Build['debug']
<Build.debug: 200>

[1] Официальные документы: Enum programmatic access

Ответ 2

Другая альтернатива (особенно полезная, если ваши строки не отображают 1-1 в ваши staticmethod enum) - это добавить staticmethod в ваш Enum, например:

class QuestionType(enum.Enum):
    MULTI_SELECT = "multi"
    SINGLE_SELECT = "single"

    @staticmethod
    def from_str(label):
        if label in ('single', 'singleSelect'):
            return QuestionType.SINGLE_SELECT
        elif label in ('multi', 'multiSelect'):
            return QuestionType.MULTI_SELECT
        else:
            raise NotImplementedError

Затем вы можете сделать question_type = QuestionType.from_str('singleSelect')

Ответ 3

def custom_enum(typename, items_dict):
    class_definition = """
from enum import Enum

class {}(Enum):
    {}""".format(typename, '\n    '.join(['{} = {}'.format(k, v) for k, v in items_dict.items()]))

    namespace = dict(__name__='enum_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition
    return result

MyEnum = custom_enum('MyEnum', {'a': 123, 'b': 321})
print(MyEnum.a, MyEnum.b)

Или вам нужно преобразовать строку в известный Enum?

class MyEnum(Enum):
    a = 'aaa'
    b = 123

print(MyEnum('aaa'), MyEnum(123))

Или:

class BuildType(Enum):
    debug = 200
    release = 400

print(BuildType.__dict__['debug'])

print(eval('BuildType.debug'))
print(type(eval('BuildType.debug')))    
print(eval(BuildType.__name__ + '.debug'))  # for work with code refactoring

Ответ 4

Улучшение в ответе @rogueleaderr:

class QuestionType(enum.Enum):
    MULTI_SELECT = "multi"
    SINGLE_SELECT = "single"

    @classmethod
    def from_str(cls, label):
        if label in ('single', 'singleSelect'):
            return cls.SINGLE_SELECT
        elif label in ('multi', 'multiSelect'):
            return cls.MULTI_SELECT
        else:
            raise NotImplementedError

Ответ 5

Мое Java-подобное решение проблемы. Надеюсь, это поможет кому-то...

from enum import Enum, auto


class SignInMethod(Enum):
    EMAIL = auto(),
    GOOGLE = auto()

    @staticmethod
    def value_of(value) -> Enum:
        for m, mm in SignInMethod.__members__.items():
            if m == value:
                return mm


sim = SignInMethod.value_of('EMAIL')
print("""TEST
1). {0}
2). {1}
3). {2}
""".format(sim, sim.name, isinstance(sim, SignInMethod)))

Ответ 6

Я просто хочу сообщить, что это не работает в Python 3.6

class MyEnum(Enum):
    a = 'aaa'
    b = 123

print(MyEnum('aaa'), MyEnum(123))

Вы должны будете предоставить данные в виде кортежа, как это

MyEnum(('aaa',))

РЕДАКТИРОВАТЬ: Это оказывается ложным. Кредиты для комментатора за указание на мою ошибку