[英]How do I keep track of Python enum values internally?
我的最終目標是在我的Enum類中創建一個輔助方法,它始終返回一個Enum成員,並且在給定任何可能的值的情況下永遠不會引發異常,例如
Color.from_value('red')
如果該值不是枚舉的一部分,則輔助方法將返回默認值,例如Color.UNKNOWN
。
根據另一個相關問題的答案 ,我可以通過一些內置成員列出值來檢查這些值。 但是,我接下來要做的是跟蹤內部成員中的所有值,這樣我就不必每次調用helper方法時都遍歷值。 我嘗試做類似以下的事情:
class Color(Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
# this doesn't work
_values = [item.value for item in Color]
正如預期的那樣,它不起作用。 這可能是已經內置在Python Enums中的東西嗎?
您可以創建方法並檢查類中的值:
import enum
class Color(enum.Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = "unknown"
@classmethod
def from_value(cls, value):
try:
return {item.value: item for item in cls}[value]
except KeyError:
return cls.UNKNOWN
print(Color.from_value("hey"))
print(Color.from_value("red"))
結果:
Color.UNKNOWN
Color.RED
這里有一個實例
如果您不想重申,您可以始終擁有值的外部緩存:
class Color(enum.Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = "unknown"
@classmethod
def from_value(cls, value):
try:
return _COLORITEMS[value]
except KeyError:
return cls.UNKNOWN
_COLORITEMS = {item.value: item for item in Color}
我已經接受了Netwave的回答,但我將其添加為原始版本的一些變化。 我想保留答案作為參考。
import enum
class Color(enum.Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = "unknown"
@staticmethod
def from_value(value):
try:
return Color(value)
except ValueError:
return cls.UNKNOWN
請注意,在這種方法中,我已經將@classmethod
更改為@staticmethod
因為我不再需要cls
參數。 另外,我在這里處理ValueError
而不是KeyError
因為這是在無法找到值的情況下Color()
引發的。 這也適用於多值/元組值枚舉。
至於第二種方法:
import enum
class Color(enum.Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = "unknown"
@staticmethod
def from_value(value):
return Color(value) if value in _COLORITEMS else Color.UNKNOWN
_COLORITEMS = [item.value for item in Color]
在這里,我從dict切換到list以跟蹤值。 我只是檢查該值是否在列表中,而不是處理KeyError
。 我可以使用一個集合,但由於它是一個枚舉,因此值保證是唯一的(如果我理解正確的話)。
您可以在內部跟蹤值,但這有點麻煩:
嘗試1
_values = [k for k in vars().keys() if not k.startswith('_')]
問題1
>>> # _values is a member
>>> Color._values
<Color._huh: ['RED', 'BLUE', 'GREEN']>
嘗試2
從這個答案中使用Constant
_values = Constant([k for k in vars().keys() if not k.startswith('_')])
問題2
它並不是真正的常量,因為你仍然可以附加到列表中 - 但這可以通過轉換為tuple
來解決:
_values = Constant(tuple([k for k in vars().keys() if not k.startswith('_')]))
但是,這仍然無法解決UNKNOWN
問題。
解
使用Python 3.6或aenum 2.0
1,您可以指定一個_missing_
方法,在提出ValueError
之前,該方法將為您的類提供最后一次機會:
class Constant: # use Constant(object) if in Python 2
def __init__(self, value):
self.value = value
def __get__(self, *args):
return self.value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.value)
class Color(Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = 'unknown'
_values = Constant(tuple([k for k in vars().keys() if not k.startswith('_')]))
@classmethod
def _missing_(cls, name):
if name.lower() in cls._values:
return cls(name.lower())
else:
return cls.UNKNOWN
要么
class Color(Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = 'unknown'
@classmethod
def _missing_(cls, name):
if name == name.lower():
# avoid infinite recursion
return cls.UNKNOWN
else:
return cls(name.lower())
注意 : _missing_
只返回enum成員或None
- 如果返回任何其他內容,Python版本將引發TypeError
。
1披露:我是Python stdlib Enum
, enum34
backport和Advanced Enumeration( aenum
)庫的作者。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.