簡體   English   中英

如何在內部跟蹤Python枚舉值?

[英]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 Enumenum34 backportAdvanced Enumeration( aenum庫的作者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM