如何覆盖枚举构造函数?

How can I override the enum constructor?

我想创建一个存储二进制值的枚举,但我可以向其传递任何值(它将存储 value % 2)。

即:我想使用 Python3 中的 "official" Enum 类型,但更改了构造函数。

我试过这段代码:

from enum import Enum

class Color(Enum):
    black = 0
    red = 1

    def __new__(cls, value):
        super().__new__(cls, value % 2)

    def __str__(self):
        return self.name

但是我得到一个错误:

>>> from ZCasino import *
ValueError: 0 is not a valid Couleur

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/felix/Téléchargements/ZCasino.py", line 12, in <module>
    class Couleur(Enum):
  File "/usr/lib/python3.8/enum.py", line 212, in __new__
    enum_member = __new__(enum_class, *args)
  File "/home/felix/Téléchargements/ZCasino.py", line 18, in __new__
    super().__new__(cls, value)
  File "/usr/lib/python3.8/enum.py", line 595, in __new__
    raise exc
  File "/usr/lib/python3.8/enum.py", line 579, in __new__
    result = cls._missing_(value)
  File "/usr/lib/python3.8/enum.py", line 608, in _missing_
    raise ValueError("%r is not a valid %s" % (value, cls.__name__))
ValueError: 0 is not a valid Couleur

您需要在 方法定义之后覆盖 __new__ 方法 :

(Is it possible to override __new__ in an enum to parse strings to an instance?)

from enum import Enum

class Color(Enum):
    black = 0
    red = 1

    def __str__(self):
        return self.name

Couleur.__new__ = lambda cls, value: super(Couleur, cls).__new__(cls, value % 2)

新的 class 方法可能比覆盖 __new__:

更好
class Color(Enum):
    black = 0
    red = 1

    @classmethod
    def from_int(cls, x):
        return cls(x%2)

然后

>>> Color.from_int(6)
<Color.black: 0>
>>> Color.from_int(7)
<Color.red: 1>

您可以利用新的 _missing_ 方法:

from aenum import Enum

class Color(Enum):
    black = 0
    red = 1
    #
    def __str__(self):
        return self.name
    #
    @classmethod
    def _missing_(cls, value):
        return cls(value % 2)

并在使用中:

>>> list(Color)
[<Color.black: 0>, <Color.red: 1>]

>>> Color(3)
<Color.red: 1>

>>> Color(8)
<Color.black: 0>

_missing_ 是在 Python 3.6 中引入的。如果您需要支持更早的 Pythons,您可以使用 aenum1 库。

NB 调用 Color(7) 时,您不是在创建新的 Color,而是获取在枚举时创建的现有 <Color.black: 0>本身已创建。


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