在Python中将字符串转换为Enum


141

我想知道将字符串转换(反序列化)为Python的Enum类的正确方法是什么。似乎可以getattr(YourEnumType, str)完成这项工作,但是我不确定它是否足够安全。

更具体地说,我想像这样将'debug'字符串转换为Enum对象:

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

Answers:


213

此功能已内置到枚举[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类并始终从该方法继承。
伊森·弗曼

@Hetzroni:按照“请求宽恕,而不是允许”的原则,您始终可以将访问权限封装在try / except KeyError子句中以返回默认值(如Ethan所述,可以选择将其包装在您自己的函数/方法中) 。
Laogeodritt

1
荣誉提名 Build('debug')
Dragonborn'Sep

2
@Dragonborn不能打电话Build('debug')。类构造函数必须走价值,即200400在这个例子中。要传递名称,必须使用方括号,如答案所示。
亚瑟·塔卡

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吗?我担心与内部Python属性发生名称冲突
。...– Vladius

哦...是的getattr。我认为没有名称冲突的原因。您只是不能将关键字设置为类的字段。
ADR 2016年

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

我只想通知这在python 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 18'Oct
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.