String-based enum in Python

有些话、适合烂在心里 提交于 2021-01-22 18:00:41

问题


To encapsulate a list of states I am using enum module:

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!)

However, the issue is that I need to seamlessly use the values as strings in many contexts in my script, like:

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

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

How to do it avoiding calling additional type conversion (str(state) above) or the underlying value (state.value)?


回答1:


It seems that it is enough to inherit from str class at the same time as Enum:

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

The tricky part is that the order of classes in the inheritance chain is important as this:

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

throws:

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

With the correct class the following operations on MyEnum are fine:

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

As a side note, it seems that the special inheritance trick is not needed for formatted strings which work even for Enum inheritance only:

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



回答2:


While a mixin class between str and Enum can solve this problem, you should always also think about getting the right tool for the job.

And sometimes, the right tool could easily just be a MODULE_CONSTANT with a string value. For example, logging has a few constants like DEBUG, INFO, etc with meaningful values - even if they're ints in this case.

Enums are a good tool and I often use them. However, they're intended to be primarily compared against other members of the same Enum, which is why comparing them to, for example, strings requires you to jump through an additional hoop.




回答3:


If associated string values are valid Python names then you can get names of enum members using .name property like this:

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

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

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

If associated string values are arbitrary strings then you can do this:

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'

Try this online: https://repl.it/@sytelus/enumstrtest




回答4:


Simply use .value :

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



回答5:


Try changing the data type of status in the database to match the enum. Some db’s do not allow, or try in a temp copy of table too.



来源:https://stackoverflow.com/questions/58608361/string-based-enum-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!