Python中基于字符串的枚举

时间:2019-10-29 13:26:55

标签: python python-3.x string enums

要封装状态列表,请使用enum模块:

from enum import Enum

class MyEnum(Enum):
    state1='state1'
    state2 = 'state2'

state = MyEnum.state1
MyEnum['state1'] == state  # here it works
'state1' == state  # here it does not throw but returns False (fail!)

但是,问题是我需要在脚本的许多上下文中将这些值无缝地用作字符串,例如:

select_query1 = select(...).where(Process.status == str(MyEnum.state1))  # works but ugly

select_query2 = select(...).where(Process.status == MyEnum.state1)  # throws exeption

如何避免调用其他类型转换(上面的str(state))或基础值(state.value)?

6 个答案:

答案 0 :(得分:4)

似乎可以同时继承str类和Enum

class MyEnum(str, Enum):
    state1='state1'
    state2 = 'state2'

棘手的部分是,继承链中的类的顺序很重要,如下所示:

class MyEnum(Enum, str):
    state1='state1'
    state2 = 'state2'

抛出:

TypeError: new enumerations should be created as `EnumName([mixin_type, ...] [data_type,] enum_type)`

使用正确的类,可以对MyEnum进行以下操作:

print('This is the state value: ' + state)

作为旁注,似乎formatted strings并不需要特殊的继承技巧,即使仅Enum继承也可以使用

msg = f'This is the state value: {state}'  # works without inheriting from str

答案 1 :(得分:1)

虽然strEnum之间的混合类可以解决此问题,但您也应该始终考虑为工作选择正确的工具

有时候,正确的工具很容易就是带有字符串值的MODULE_CONSTANT。例如,logging具有一些常量,例如DEBUG,INFO等,具有有意义的值-即使在这种情况下它们是int

枚举是一个很好的工具,我经常使用它们。但是,它们主要是与同一个Enum的其他成员进行比较的,因此这就是为什么将它们与例如字符串进行比较需要您跳过另一个箍的原因。

答案 2 :(得分:1)

如果关联的字符串值是有效的 Python 名称,那么您可以使用 .name 属性获取枚举成员的名称,如下所示:

from enum import Enum
class MyEnum(Enum):
    state1=0
    state2=1

print (MyEnum.state1.name)  # 'state1'

a = MyEnum.state1
print(a.name)  # 'state1'

如果关联的字符串值是任意字符串,那么您可以这样做:

class ModelNames(str, Enum):
    gpt2 = 'gpt2'
    distilgpt2 = 'distilgpt2'
    gpt2_xl = 'gpt2-XL'
    gpt2_large = 'gpt2-large'

print(ModelNames.gpt2) # 'ModelNames.gpt2'
print(ModelNames.gpt2 is str) # False
print(ModelNames.gpt2_xl.name) # 'gpt2_xl'
print(ModelNames.gpt2_xl.value) # 'gpt2-XL'

在线试用:https://repl.it/@sytelus/enumstrtest

答案 3 :(得分:1)

如果你想直接处理字符串,可以考虑使用

MyEnum = collections.namedtuple(
    "MyEnum", ["state1", "state2"]
)(
    state1="state1", 
    state2="state2"
)

而不是枚举。迭代这个或执行 MyEnum.state1 将直接给出字符串值。在同一个语句中创建 namedtuple 意味着只能有一个。

显然,不使用 Enum 会有一些折衷,所以这取决于您更看重什么。

答案 4 :(得分:0)

尝试更改数据库中状态的数据类型以匹配枚举。某些数据库不允许,也可以尝试使用临时表。

答案 5 :(得分:-1)

只需使用 .value :

MyEnum.state1.value == 'state1'
# True