在 python 中列出所有枚举项(包括基类中的项)

List all Enum items (including the one from base class) in python

提问人:Martin 提问时间:10/11/2023 最后编辑:Martin 更新时间:10/12/2023 访问量:57

问:

我想用一个方法列出所有枚举项。该方法在基类中定义为类函数。 基类具有子类,子类具有其他子类。 我使用了 python 扩展 extendable-enum。

我更新了示例代码:

from enum import Enum
from extendableenum import inheritable_enum
import inspect


@inheritable_enum
class baseClass(Enum):
    BASEELEMENT= 'Baseelement'

    @classmethod
    def list(cls):
        classHierachy = inspect.getmro(cls)
        for singleClass in classHierachy[0:-2]:
            print(singleClass.__name__)  # debug output
            print(list(map(lambda singleClass: singleClass.name, eval(singleClass.__name__))))

    def get_list_with_bases(class1, output=None):
        if output is None:
            output = []
        try:
            names = list(class1)
        except TypeError:
            return output
        for class2 in class1.__bases__:
            get_list_with_bases(class2, output)
        output.extend(names)
        return output


@inheritable_enum
class middleClass(baseClass):
    MIDDLECLASSELEMENT = 'middleClassElement'

class endClass(middleClass, baseClass):
    ENDCLASSELEMENT = 'endClassElement'


print(endClass.BASEELEMENT)
print(endClass.MIDDLECLASSELEMENT)
print(endClass.ENDCLASSELEMENT)
endClass.list()
# endClass.get_list_with_bases(endClass)

预期输出:

baseClass.BASEELEMENT
middleClass.MIDDLECLASSELEMENT
endClass.ENDCLASSELEMENT
endClass
['ENDCLASSELEMENT']
middleClass
MIDDLECLASSELEMENT
baseClass
BASEELEMENT

但我得到:

baseClass.BASEELEMENT
middleClass.MIDDLECLASSELEMENT
endClass.ENDCLASSELEMENT
endClass
['ENDCLASSELEMENT']
middleClass
[]
baseClass
[]
Python 枚举 派生类

评论

1赞 Barmar 10/11/2023
没有必要使用 .这和刚才一样。eval(cls.__name__)cls
1赞 Grismar 10/11/2023
你想让它理解它吗?因为要做你想做的事情,你只需要一个,使用似乎非常复杂。此外,您的示例中有一个错别字(但显然不是在您运行的代码中 - 这表明您没有共享您正在运行的实际代码)- “TEWNTYTWO”。dictextendable-enum

答:

2赞 Dakolas 10/11/2023 #1

根据项目存储库中提供的示例,它看起来无法以这种方式访问

https://github.com/gweesip/extendable-enum/blob/main/docs/examples/example_inheritable_enum.py

# And create a subclass with new members
class MoreFruit(Fruit):
    MANGO = 4
    DRAGONFRUIT = 5

# Only the non-inherited members will be in _member_names_
print(MoreFruit._member_names_)

# Inherited members are not included in dir, len, reversed or iteration
print(dir(MoreFruit))
print(len(MoreFruit))
print([member for member in reversed(MoreFruit)])
print([member for member in MoreFruit])

# Inherited members can not be accessed by name
try:
    MoreFruit['APPLE']
except KeyError:
    print('Access to super members by name not supported')

# or by value
try:
    MoreFruit(1)
except ValueError:
    print('Access by value not allowed')

# but can still be accessed as attributes.
print(MoreFruit.APPLE)
# The returned members are the superclass members.
print(MoreFruit.APPLE is Fruit.APPLE)
1赞 pts 10/11/2023 #2

根据 @Dakolas 的回答,没有直接的方法可以列出所有枚举名称。

用作解决方法:.__bases__

# And create a subclass with new members
class MoreFruit(Fruit):
    MANGO = 4
    DRAGONFRUIT = 5

print(list(MoreFruit) + list(MoreFruit.__bases__[0]))

作为更通用的解决方案,编写一个递归函数来访问所有级别的所有基类:

def get_list_with_bases(class1, output=None):
  if output is None:
    output = []
  try:
    names = list(class1)
  except TypeError:
    return output
  for class2 in class1.__bases__:
    get_list_with_bases(class2, output)
  output.extend(names)
  return output

# And create a subclass with new members
class MoreFruit(Fruit):
    MANGO = 4
    DRAGONFRUIT = 5

print(get_list_with_bases(MoreFruit))

评论

0赞 Martin 10/12/2023
嗨,pts,递归函数在我这边不起作用。我收到错误:NameError:未定义名称“get_list_with_bases”。
0赞 pts 10/12/2023
它对我有用,也许你复制粘贴不正确。
1赞 Grismar 10/11/2023 #3

如果您试图理解代码的问题,它通常有助于使代码更简单。

这与你的代码非常相似,但大大简化了:

from enum import Enum
from extendableenum import inheritable_enum


@inheritable_enum
class ExampleA(Enum):
    A = 1


class ExampleAB(ExampleA):
    B = 2


print(ExampleAB.A, ExampleAB.A.value)
print(ExampleAB.B, ExampleAB.B.value)

for x in ExampleAB:
    print('x:', x)

不是多个类添加东西,而是有一个简单的基类,它只有 value 。以及其中也具有 value 的派生类。ExampleAA1ExampleABB2

而不是你拥有的方法,它可以像用户@Barmar在评论中指出的那样写成这样:

    @classmethod
    def list(cls):
        return list(map(lambda c: c.name, cls))

我刚刚在末尾添加了一个简单的循环,该循环还遍历枚举中的所有内容并显示里面的内容。for

输出:

ExampleA.A 1
ExampleAB.B 2
x: ExampleAB.B

这清楚地表明:

  • ExampleAB确实使这两个类的值都可用。
  • 的实际值仍然来自超类。ExampleAB.AExampleA.A
  • 如果遍历 ExampleAB,它实际上只包含 ,它不会包含基类中的值。ExampleAB.B

但是,如果您只想要此功能,那么 a 当然会是一个更简单、更好的选择:dict

exampleA = {
    'A': 1
}

exampleAB = exampleA | {
    'B': 2
}

print(exampleAB['A'])
print(exampleAB['B'])

for x in exampleAB:
    print('x:', x, 'value:', exampleAB[x])

输出:

1
2
x: A value: 1
x: B value: 2

评论

0赞 Martin 10/12/2023
嗨,格里斯玛,我想得到所有等级的枚举。我用这个函数尝试了一下,但结果是一样的。即使我单独针对每个班级:我也会将其作为回复发布