在Python中将字符串转换为Enum

Vla*_*ius 102 python string enums serialization type-conversion

我想知道将字符串转换(反序列化)到Python的Enum类的正确方法是什么.好像getattr(YourEnumType, str)工作似乎,但我不确定它是否足够安全.

更具体地说,我想将'debug'字符串转换为Enum对象,如下所示:

class BuildType(Enum):
    debug = 200
    release = 400
Run Code Online (Sandbox Code Playgroud)

Eth*_*man 151

此功能已内置于Enum [1]中:

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

[1]官方文件: Enum programmatic access

  • @Dragonborn 调用 `Build('debug')` 是行不通的。类构造函数必须采用*值*,即本例中的“200”或“400”。要传递*名称*,您必须使用方括号,正如答案已经说过的那样。 (7认同)
  • 如果需要清理输入,回退值又如何呢?诸如“ Build.get('illegal',Build.debug)`”之类的东西吗? (3认同)
  • @Hetzroni:根据“请求宽恕,而不是请求许可”原则,您始终可以将访问包含在 try/ except KeyError 子句中以返回默认值(正如 Ethan 提到的,可以选择将其包装在您自己的函数/方法中) 。 (3认同)

rog*_*err 14

另一种选择(如果你的字符串不映射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
Run Code Online (Sandbox Code Playgroud)

那你可以做 question_type = QuestionType.from_str('singleSelect')

  • 有没有办法覆盖`__getitem__`或其他内置方法? (2认同)

Mit*_*tch 8

我的类似Java的问题解决方案。希望它可以帮助某人...

from enum import Enum, auto


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

    @classmethod
    def value_of(cls, value):
        for k, v in cls.__members__.items():
            if k == value:
                return v
        else:
            raise ValueError(f"'{cls.__name__}' enum not found for '{value}'")


sim = SignInMethod.value_of('EMAIL')
assert sim == SignInMethod.EMAIL
assert sim.name == 'EMAIL'
assert isinstance(sim, SignInMethod)
# SignInMethod.value_of("invalid sign-in method")  # should raise `ValueError`
Run Code Online (Sandbox Code Playgroud)


ADR*_*ADR 5

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)
Run Code Online (Sandbox Code Playgroud)

还是需要将字符串转换为已知的 Enum?

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

print(MyEnum('aaa'), MyEnum(123))
Run Code Online (Sandbox Code Playgroud)

要么:

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
Run Code Online (Sandbox Code Playgroud)