问题
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 int
s 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