类型为“type”的枚举类作为mixin
Posted
技术标签:
【中文标题】类型为“type”的枚举类作为mixin【英文标题】:Enum class with type `type` as mixin 【发布时间】:2021-03-16 07:50:19 【问题描述】:docs 声明可以通过将某个类型作为 mixin 添加到枚举类中来创建一个其成员完全属于某种类型的枚举类:
虽然 :class:
IntEnum
是 :mod:enum
模块的一部分,但它会是 独立实现非常简单::class IntEnum(int, Enum): pass
这演示了如何定义相似的派生枚举;为了 例如一个 :class:
StrEnum
混入 :class:str
而不是 :class:int
.一些规则:
当子类化 :class:
Enum
时,混合类型必须出现在 :class:Enum
本身之前的基序列中,如 :class:IntEnum
上面的例子。 虽然 :class:Enum
可以有任何类型的成员,但一旦混合了其他类型,所有成员都必须具有该类型的值, 例如:class:int
以上。此限制不适用于 仅添加方法而不指定其他类型的混入。 当混入另一种数据类型时,:attr:value
属性与枚举成员本身不同,尽管它是等价的并且会比较相等。 %-style格式:%s
和%r
分别调用:class:Enum
类的:meth:__str__
和:meth:__repr__
;其他代码(例如 如%i
或%h
for IntEnum) 将枚举成员视为其混合 输入。 :ref:Formatted string literals <f-strings>
、:meth:str.format
和:func:format
将使用混合类型的:meth:__format__
除非 :meth:__str__
或 :meth:__format__
在 子类,在这种情况下被覆盖的方法或 :class:Enum
会用到方法。使用 !s 和 !r 格式代码强制使用 :class:Enum
类的 :meth:__str__
和 :meth:__repr__
方法。
我试图创建一个枚举,其成员是类型(type
类型的对象),但由于 type
是一个特殊的类(它是一个元类而不是一个类),我得到了一堆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
类层次结构;每个子类代表不同的卡片类型。但是,游戏中的卡牌类型与Card
的子类之间的映射可能不是一对一的;例如,可能有一些中间抽象类用作实现帮助,但不代表实际的卡片类型。
所以我想创建一个包含所有游戏卡类型的枚举,并且我希望成员是实现这些类型的实际具体子类,以便我可以轻松地互操作枚举成员和实际类:想法是访问类属性、实例化它们等,而不必每次都使用.value
(因为在某些情况下,我可能不得不使用枚举成员或类本身的东西)。
【问题讨论】:
即使事实证明这是可能的,生成的枚举成员的语义也会过于混乱。不同的设计会是更好的主意。 在您的示例中,您重复使用密钥EGGS
,这会导致错误。
@Anakhand:反之亦然。你可以有FOO=1
和BAR=1
,但不能有FOO=1
和FOO=2
。
别名是同一个值的另一个名字,不是两个值的同一个名字
啊,你是完全正确的,出于某种原因,我脑子里突然出现了这种情况。我已经更正了这个例子。无论如何,这与问题无关。
【参考方案1】:
简短回答:不,目前无法将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
、enum34
backport 和 Advanced Enumeration (aenum
) 库的作者。
【讨论】:
我意识到这可能是一个 XY 问题,所以我在编辑我的问题时解释了我的具体用例。以上是关于类型为“type”的枚举类作为mixin的主要内容,如果未能解决你的问题,请参考以下文章
类型“Favorites.Type”不能符合“Encodable”;只有结构/枚举/类类型可以符合协议
type() 不能符合 View;只有结构/枚举/类类型可以符合协议