枚举 class,类型为 `type` 作为 mixin
Enum class with type `type` as mixin
docs 声明可以创建一个枚举 class,其成员恰好是某种类型,方法是将该类型作为混合类型添加到枚举 class 中:
While :class:IntEnum
is part of the :mod:enum
module, it would be
very simple to implement independently::
class IntEnum(int, Enum):
pass
This demonstrates how similar derived enumerations can be defined; for
example a :class:StrEnum
that mixes in :class:str
instead of
:class:int
.
Some rules:
- When subclassing :class:
Enum
, mix-in types must appear before :class:Enum
itself in the sequence of bases, as in the
:class:IntEnum
example above.
- While :class:
Enum
can have members of any type, once you mix in an additional type, all the members must have values of that type,
e.g. :class:int
above. This restriction does not apply to
mix-ins which only add methods and don't specify another type.
- When another data type is mixed in, the :attr:
value
attribute is not the same as the enum member itself, although it is equivalent and will compare equal.
- %-style formatting:
%s
and %r
call the :class:Enum
class's :meth:__str__
and :meth:__repr__
respectively; other codes (such
as %i
or %h
for IntEnum) treat the enum member as its mixed-in
type.
- :ref:
Formatted string literals <f-strings>
, :meth:str.format
, and :func:format
will use the mixed-in type's :meth:__format__
unless :meth:__str__
or :meth:__format__
is overridden in the
subclass, in which case the overridden methods or :class:Enum
methods will be used. Use the !s and !r format codes to force usage
of the :class:Enum
class's :meth:__str__
and :meth:__repr__
methods.
我试图创建一个枚举,其成员是类型(type
类型的对象),但由于 type
是一个特殊的 class(它是一个元 class 多于 class),我收到了一堆错误,例如 mro
、__new__
、__init__
等的参数不匹配:
import enum
class A: pass
class B: pass
class C(B): pass
class MyTypes(type, enum.Enum):
SPAM = A
EGGS = C
错误示例:
Traceback (most recent call last):
File "<file>", line 10, in <module>
class MyTypes(type, enum.Enum):
File "<file>", line 182, in __new__
dynamic_attributes = {k for c in enum_class.mro()
TypeError: descriptor 'mro' of 'type' object needs an argument
有办法实现吗?
我意识到这可能是一个 XY 问题,所以我将解释我的具体示例。在我正在开发的纸牌游戏中,我有一个 Card
class 层次结构;每个 subclasses 代表不同的卡片类型。但是,游戏中的卡牌类型与Card
的子class卡牌类型之间的映射可能不是一对一的;例如,可能有一些中间抽象 classes 作为实现帮助,但不代表实际的卡类型。
所以我想做一个包含所有游戏卡类型的枚举,我希望成员是实现这些类型的实际具体子classes,这样我就可以轻松地互操作枚举成员和实际的 classes:这个想法是访问 class 属性,实例化它们,等等,而不必每次都使用 .value
(因为在某些情况下,我可能不得不使用一些东西是枚举的成员或 class 本身)。
简短回答:不,目前无法将 type
混入枚举。
混合数据类型的目的有两个:
- 确保所有成员都是该类型
class Number(int, Enum):
ONE = 1
TWO = 2
THREE = 'three'
# ValueError: invalid literal for int() with base 10: 'three'
- 使成员可以直接用作该类型
class Number(int, Enum):
ONE = 1
TWO = 2
Number.ONE + 2
# 3
如您所述,type
不是一种数据类型——它是一种元类。它需要特殊支持才能工作。您的用例是什么?
披露:我是 Python stdlib Enum
, the enum34
backport, and the Advanced Enumeration (aenum
) 库的作者。
docs 声明可以创建一个枚举 class,其成员恰好是某种类型,方法是将该类型作为混合类型添加到枚举 class 中:
While :class:
IntEnum
is part of the :mod:enum
module, it would be very simple to implement independently::class IntEnum(int, Enum): pass
This demonstrates how similar derived enumerations can be defined; for example a :class:
StrEnum
that mixes in :class:str
instead of :class:int
.Some rules:
- When subclassing :class:
Enum
, mix-in types must appear before :class:Enum
itself in the sequence of bases, as in the :class:IntEnum
example above.- While :class:
Enum
can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. :class:int
above. This restriction does not apply to mix-ins which only add methods and don't specify another type.- When another data type is mixed in, the :attr:
value
attribute is not the same as the enum member itself, although it is equivalent and will compare equal.- %-style formatting:
%s
and%r
call the :class:Enum
class's :meth:__str__
and :meth:__repr__
respectively; other codes (such as%i
or%h
for IntEnum) treat the enum member as its mixed-in type.- :ref:
Formatted string literals <f-strings>
, :meth:str.format
, and :func:format
will use the mixed-in type's :meth:__format__
unless :meth:__str__
or :meth:__format__
is overridden in the subclass, in which case the overridden methods or :class:Enum
methods will be used. Use the !s and !r format codes to force usage of the :class:Enum
class's :meth:__str__
and :meth:__repr__
methods.
我试图创建一个枚举,其成员是类型(type
类型的对象),但由于 type
是一个特殊的 class(它是一个元 class 多于 class),我收到了一堆错误,例如 mro
、__new__
、__init__
等的参数不匹配:
import enum
class A: pass
class B: pass
class C(B): pass
class MyTypes(type, enum.Enum):
SPAM = A
EGGS = C
错误示例:
Traceback (most recent call last):
File "<file>", line 10, in <module>
class MyTypes(type, enum.Enum):
File "<file>", line 182, in __new__
dynamic_attributes = {k for c in enum_class.mro()
TypeError: descriptor 'mro' of 'type' object needs an argument
有办法实现吗?
我意识到这可能是一个 XY 问题,所以我将解释我的具体示例。在我正在开发的纸牌游戏中,我有一个 Card
class 层次结构;每个 subclasses 代表不同的卡片类型。但是,游戏中的卡牌类型与Card
的子class卡牌类型之间的映射可能不是一对一的;例如,可能有一些中间抽象 classes 作为实现帮助,但不代表实际的卡类型。
所以我想做一个包含所有游戏卡类型的枚举,我希望成员是实现这些类型的实际具体子classes,这样我就可以轻松地互操作枚举成员和实际的 classes:这个想法是访问 class 属性,实例化它们,等等,而不必每次都使用 .value
(因为在某些情况下,我可能不得不使用一些东西是枚举的成员或 class 本身)。
简短回答:不,目前无法将 type
混入枚举。
混合数据类型的目的有两个:
- 确保所有成员都是该类型
class Number(int, Enum):
ONE = 1
TWO = 2
THREE = 'three'
# ValueError: invalid literal for int() with base 10: 'three'
- 使成员可以直接用作该类型
class Number(int, Enum):
ONE = 1
TWO = 2
Number.ONE + 2
# 3
如您所述,type
不是一种数据类型——它是一种元类。它需要特殊支持才能工作。您的用例是什么?
披露:我是 Python stdlib Enum
, the enum34
backport, and the Advanced Enumeration (aenum
) 库的作者。