파이썬에서 문자열을 Enum으로 변환


141

문자열을 Python의 Enum 클래스로 변환 (직렬화)하는 올바른 방법이 무엇인지 궁금합니다. 일을하는 것처럼 보이지만 getattr(YourEnumType, str)그것이 충분히 안전한지 확실하지 않습니다.

좀 더 구체적으로 말하면 다음과 같이 'debug'문자열을 Enum 객체 로 변환하고 싶습니다.

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

답변:


213

이 기능은 이미 Enum [1]에 내장되어 있습니다.

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

[1] 공식 문서 : Enum programmatic access


6
입력을 위생 처리해야하는 경우 대체 값은 어떻습니까? 일종의 뭔가 Build.get('illegal', Build.debug)?
Hetzroni

1
@Hetzroni : 메소드 Enum가 제공되지 .get()않지만 필요에 따라 메소드를 추가하거나 기본 Enum클래스를 작성하여 항상 상속 할 수 있습니다.
Ethan Furman

@Hetzroni : "권한이 아닌 용서 요청"원칙에 따라 항상 try / except KeyError 절에 액세스를 포함시켜 기본값을 반환 할 수 있습니다 (Ethan이 언급 한대로 선택적으로 자신의 함수 / 방법으로 래핑) .
Laogeodritt

1
존경 할만한 언급 Build('debug')
Dragonborn

2
@Dragonborn 전화를 거는 것은 효과가 없습니다 Build('debug'). 클래스 생성자는 값을 가져야합니다 ( 예 : 200또는 400이 예). 이름 을 전달하려면 답이 이미 말한 것처럼 대괄호를 사용해야합니다.
Arthur Tacca

17

또 다른 대안 (특히 문자열이 1-1을 열거 형 사례에 매핑하지 않는 경우에 유용합니다)는에 다음을 추가하는 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')


1
당신 자신은 종종이 일을 발견하면 매우 관련 : pydantic-docs.helpmanual.io
driftcatcher

6
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

debug문자열을 다음과 같은 열거 형 으로 변환하고 싶습니다 . python class BuildType(Enum): debug = 200 release = 400
Vladius

좋은 팁! __dict__와 같은 것을 사용 하고 getattr있습니까? 내부 파이썬 속성과의 이름 충돌에 대해 걱정하고 있습니다. ...
Vladius

아 .. 예와 같습니다 getattr. 이름 충돌의 이유가 없습니다. 키워드를 클래스의 필드로 설정할 수 없습니다.
ADR

4

문제에 대한 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.upper():
                    return mm


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

2

@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

-2

파이썬 3.6에서는 작동하지 않습니다.

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

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

이처럼 튜플로 데이터를 제공해야합니다.

MyEnum(('aaa',))

편집 : 이것은 거짓으로 판명되었습니다. 내 실수를 지적한 해설자에게 크레딧


Python 3.6.6을 사용하면이 동작을 재현 할 수 없었습니다. 테스트하는 동안 실수를 한 것 같습니다 (이를 확인할 때 처음으로 한 것으로 알고 있습니다). ,각 요소 다음에 실수로 (쉼표)를 넣으면 (요소가 목록 인 것처럼) 각 요소를 튜플로 취급합니다. ( a = 'aaa',실제로와 동일 a = ('aaa',))
Multihunter

당신 말이 맞아요, 그것은 내 코드에서 다른 버그였습니다. 나는 어떻게 든 당신이 넣어 필요하다고 생각 ,어떻게 든 튜플에 값을 설정 열거 정의하는 동안 모든 라인을 뒤에
Sstuber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.