"Other"/python 枚举上的默认名称行为
"Other"/Default-name behavior on a python Enum
我试图在 python "enum" 中实现以下行为(到目前为止没有成功):
给定枚举 class
class MyEnum(enum.Enum):
A=1
B=2
C=3
我想要一个 "Other" 成员,这样 MyEnum(5)
将被解释为 "Other",同时保留值 5,或者
>>> str(MyEnum(5))
... "<MyEnum.Other: 5>"
我想过重写 _missing_
函数,但我不知道如何在不重写 [=17] 的情况下创建 MyEnum
的 "custom" 实例=].
建议将不胜感激。
编辑: 在一些未能准确理解我的问题的评论之后,我不希望枚举有默认值,因为此默认值不会保留该值(我希望保留)。我只希望使用默认名称接受该值。
这看起来像您要的:
>>> class Yep(enum.IntFlag):
... A = 1
... B = 2
...
>>> Yep(5)
<Yep.4|A: 5>
所以,Yep(5)
是有效的,但是不会有Yep.Other
魔法成员。
俗话说,如果你想做某事...我创建了以下枚举子class(我没有添加任何新成员,所以这是允许的):
class DefaultNameEnum(Enum):
"""Support for "Other"/default-name values"""
@classmethod
def _missing_(cls, value):
possible_member = cls._value2member_map_.get(value, None)
if possible_member is None:
possible_member = cls._create_pseudo_member_(value)
return possible_member
@classmethod
def _create_pseudo_member_(cls, value):
"""
Create a default-name member.
"""
default_member = cls._value2member_map_.get(None, None)
if default_member is None:
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
# construct a singleton enum pseudo-member
other_member = object.__new__(cls)
other_member._name_ = default_member._name_
other_member._value_ = value
# use setdefault in case another thread already created a composite
# with this value
other_member = cls._value2member_map_.setdefault(value, other_member)
return other_member
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(other, DefaultNameEnum):
return self._name_ == other._name_
return False
def __ne__(self, other):
return not self == other
这是基于 Flag
枚举子 class。实际上,它的用法非常简单 - 只需定义为 None
您希望将其作为默认名称即可。最好用一个例子来说明 - 考虑 class:
class ABC(DefaultNameEnum):
A = 1
B = 2
C = 3
Other = None
然后,以下控制台调用将给出:
>>> print([repr(mem) for mem in ABC])
... ['<ABC.A: 1>', '<ABC.B: 2>', '<ABC.C: 3>', '<ABC.Other: None>']
>>> ABC(123)
... '<ABC.Other: 123>'
>>> ABC(1) == ABC(2)
... False
>>> ABC(123) == ABC.Other
... True
>>> ABC(123) == ABC(1374)
... True
如果您希望获取并使用此实现,请注意以下几点:
最后一行中的行为可能需要也可能不需要 - 取决于您的使用情况。如果这是不需要的用法,只需更改 __eq__
方法以在 self._value_
或 other._value_
为 None
.
时比较名称
如果您使用此 class,为了可表示性,您可能希望默认值的 __repr__
输出 '<ABC.Other>'
而不是 '<ABC.Other: None>'
在 None
值的情况下。这可以通过覆盖 __repr__
方法轻松实现。
如果您没有定义默认成员,class 将在根据未知值调用它时引发异常(就像任何 Enum
subclass).
我还想指出,在上面的实现中,我更愿意使用拆分成员,例如 _default_name_
或 _default_value_member_
而不是分配 None
,但是唉enum
模块不允许为 Enum
subclasses 定义新的拆分成员。
我试图在 python "enum" 中实现以下行为(到目前为止没有成功):
给定枚举 class
class MyEnum(enum.Enum):
A=1
B=2
C=3
我想要一个 "Other" 成员,这样 MyEnum(5)
将被解释为 "Other",同时保留值 5,或者
>>> str(MyEnum(5))
... "<MyEnum.Other: 5>"
我想过重写 _missing_
函数,但我不知道如何在不重写 [=17] 的情况下创建 MyEnum
的 "custom" 实例=].
建议将不胜感激。
编辑: 在一些未能准确理解我的问题的评论之后,我不希望枚举有默认值,因为此默认值不会保留该值(我希望保留)。我只希望使用默认名称接受该值。
这看起来像您要的:
>>> class Yep(enum.IntFlag):
... A = 1
... B = 2
...
>>> Yep(5)
<Yep.4|A: 5>
所以,Yep(5)
是有效的,但是不会有Yep.Other
魔法成员。
俗话说,如果你想做某事...我创建了以下枚举子class(我没有添加任何新成员,所以这是允许的):
class DefaultNameEnum(Enum):
"""Support for "Other"/default-name values"""
@classmethod
def _missing_(cls, value):
possible_member = cls._value2member_map_.get(value, None)
if possible_member is None:
possible_member = cls._create_pseudo_member_(value)
return possible_member
@classmethod
def _create_pseudo_member_(cls, value):
"""
Create a default-name member.
"""
default_member = cls._value2member_map_.get(None, None)
if default_member is None:
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
# construct a singleton enum pseudo-member
other_member = object.__new__(cls)
other_member._name_ = default_member._name_
other_member._value_ = value
# use setdefault in case another thread already created a composite
# with this value
other_member = cls._value2member_map_.setdefault(value, other_member)
return other_member
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(other, DefaultNameEnum):
return self._name_ == other._name_
return False
def __ne__(self, other):
return not self == other
这是基于 Flag
枚举子 class。实际上,它的用法非常简单 - 只需定义为 None
您希望将其作为默认名称即可。最好用一个例子来说明 - 考虑 class:
class ABC(DefaultNameEnum):
A = 1
B = 2
C = 3
Other = None
然后,以下控制台调用将给出:
>>> print([repr(mem) for mem in ABC]) ... ['<ABC.A: 1>', '<ABC.B: 2>', '<ABC.C: 3>', '<ABC.Other: None>'] >>> ABC(123) ... '<ABC.Other: 123>' >>> ABC(1) == ABC(2) ... False >>> ABC(123) == ABC.Other ... True >>> ABC(123) == ABC(1374) ... True
如果您希望获取并使用此实现,请注意以下几点:
最后一行中的行为可能需要也可能不需要 - 取决于您的使用情况。如果这是不需要的用法,只需更改
__eq__
方法以在self._value_
或other._value_
为None
. 时比较名称
如果您使用此 class,为了可表示性,您可能希望默认值的
__repr__
输出'<ABC.Other>'
而不是'<ABC.Other: None>'
在None
值的情况下。这可以通过覆盖__repr__
方法轻松实现。如果您没有定义默认成员,class 将在根据未知值调用它时引发异常(就像任何
Enum
subclass).
我还想指出,在上面的实现中,我更愿意使用拆分成员,例如 _default_name_
或 _default_value_member_
而不是分配 None
,但是唉enum
模块不允许为 Enum
subclasses 定义新的拆分成员。