可以在 Enum 中添加自定义错误以显示有效值吗?

Can one add a custom error in Enum to show valid values?

假设我有

from enum import Enum

class SomeType(Enum):
    TYPEA = 'type_a'
    TYPEB = 'type_b'
    TYPEC = 'type_c'

如果我现在做

SomeType('type_a')

我会得到

<SomeType.TYPEA: 'type_a'>

符合预期。当我这样做时

SomeType('type_o')

我会收到

ValueError: 'type_o' is not a valid SomeType

这也在意料之中。

我的问题是:是否可以通过某种方式轻松自定义错误以使其显示所有有效类型?所以,就我而言,我想

ValueError: 'type_o' is not a valid SomeType. Valid types are 'type_a', 'type_b', 'type_c'.

使用_missing_方法:

from enum import Enum

class SomeType(Enum):
    TYPEA = 'type_a'
    TYPEB = 'type_b'
    TYPEC = 'type_c'
    @classmethod
    def _missing_(cls, value):
        raise ValueError(
                '%r is not a valid %s.  Valid types: %s' % (
                    value,
                    cls.__name__,
                    ', '.join([repr(m.value) for m in cls]),
                    ))

并在使用中:

>>> SomeType('type_a')
<SomeType.TYPEA: 'type_a'>

>>> SomeType('type_o')
ValueError: 'type_o' is not a valid SomeType

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
ValueError: 'type_o' is not a valid SomeType.  Valid types: 'type_a', 'type_b', 'type_c'

如您所见,异常链接有点笨拙,因为 Enum 本身会引发“主要”ValueError,您丢失的错误在链中。根据您的需要,您可以缩小在 _missing_ 中提出的 ValueError 以仅包含有效类型:

from enum import Enum

class SomeType(Enum):
    TYPEA = 'type_a'
    TYPEB = 'type_b'
    TYPEC = 'type_c'
    @classmethod
    def _missing_(cls, value):
        raise ValueError(
                'Valid types: %s' % (
                    ', '.join([repr(m.value) for m in cls]),
                    )

并在使用中:

>>> SomeType('type_o')
ValueError: 'type_o' is not a valid SomeType

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
ValueError: Valid types: 'type_a', 'type_b', 'type_c'

披露:我是 Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) 库的作者。