【问题标题】:Python Enum combinationPython枚举组合
【发布时间】:2018-02-14 20:06:54
【问题描述】:

我想基于两个现有的类创建一个新的 Enum (IntEnum) 类。有一个可行的解决方案,如下所示:

from enum import unique, IntEnum
from itertools import chain
from collections import OrderedDict

@unique
class FirstEnumClass(IntEnum):
    a = 1
    b = 2

@unique
class SecondEnumClass(IntEnum):
    c = 3
    d = 4

# here a combined class is created:
CombinedEnumClass = unique(IntEnum('CombinedEnumClass', OrderedDict([(i.name, i.value) for i in chain(FirstEnumClass, SecondEnumClass)])))

我的问题:有没有一种奇特的方法来实现这一点,以便有一个适当的类定义?喜欢覆盖一些元类方法,还是这样?我想要这样的东西,这样也可以给出文档字符串:

@unique
class CombinedEnumClass(IntEnum):
    """ docstring """
    # magic needed here

有什么想法吗?谢谢!

【问题讨论】:

  • 你不需要OrderedDict,你可以只给出列表理解。
  • 我知道,它就是这样工作的,问题是我正在使用 PyCharm,如果只给出一个列表,它会发出警告:“预期类型 'Integral',得到 'List[Tuple [Any, Any]]' 代替”,OrderedDict 解决了这个问题。但是,确实,没有它它就可以工作。无论如何,我仍然无法像类定义一样做到这一点。

标签: python enums metaprogramming python-3.5 metaclass


【解决方案1】:

Python 2

使用vars() 的技巧可以完成:

class CombinedEnum(IntEnum):
    """ doc string """
    cls = vars()
    for member in chain(list(FirstEnumClass), list(SecondEnumClass)):
        cls[member.name] = member.value
    del member, cls

print(list(CombinedEnum))

之所以有效,是因为:

  • vars() 返回当前命名空间
  • 修改命名空间会修改类

我们删除membercls,因为我们不希望他们成为会员。


Python 3

以上内容(还)不适用于 Python3 3.4 和 3.5 中的新 Enum(不确定 3.6)。解决方法是改用aenum,这让我们可以告诉Enum 忽略某些名称:

from aenum import IntEnum

class CombinedEnum(IntEnum):
    """ doc string """
    _ignore_ = 'member cls'
    cls = vars()
    for member in chain(list(FirstEnumClass), list(SecondEnumClass)):
        cls[member.name] = member.value

1 披露:我是Python stdlib Enumenum34 backportAdvanced Enumeration (aenum) 库的作者。

【讨论】:

  • 看起来不错,但对我不起作用:File "C:\Anaconda3\lib\enum.py", line 66, in __setitem__ raise TypeError('Attempted to reuse key: %r' % key) TypeError: Attempted to reuse key: 'member' 我试图跳过cls[member.name] = member.value 行并写一个pass,但仍然提出了相同的问题。我使用 Python 3.5.2 和 Anaconda3。
  • 我在 Python 2.7 中尝试过,它在那里工作。你知道 Python 3.x 的方法吗?
  • @waszil:感谢您发现这一点。我添加了一个 Python 3 解决方法。
  • @EthanFurman,那你为什么要[限制枚举的子类化?](docs.python.org/3/library/…)。 _ignore_ var 在做什么?感谢您的图书馆。
  • @OwlMax:子类化增加了平等和身份的复杂性,我们认为允许它不是一个净赢; _ignore_ 变量告诉 Enum 元类从最终枚举类中丢弃这些名称。
【解决方案2】:

图书馆prevents explicitly 这样做:

仅当枚举不包含子类时才允许对枚举进行子类化 定义任何成员。

允许定义成员的枚举的子类化将导致 违反类型和实例的一些重要不变量。在 另一方面,允许共享一些常见行为是有意义的 在一组枚举之间。

因此,我发现Stackoverflow answer 使用的解决方法与您几乎相同。我认为这是唯一的方法。

【讨论】:

  • 是的,看来这是唯一的方法。与此同时,我尝试了类似this post 的方法,将 EnumMeta 元类本身子类化并使用其__new__ 方法,但最终所有尝试都遇到了同样的问题:TypeError: Cannot extend enumerations
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-19
  • 2011-04-09
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多