关于字典:在Python3.5中初始化内部类(枚举)中的静态/类列表/字典

Initialization of static/class lists/dictionaries in inner class(enum) in Python 3.5

是否可以像其他变量一样在内部枚举类中初始化静态/类字典?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# file Outer.py
from enum import Enum
class Outer:
    def callInner(self):
        all_a = Outer.Inner.ALL
        print(all_a) # prints Inner.ALL instead of the list
        all_b = Outer.Inner.ALL[:] # TypeError Inner is not subscriptable

        for e in all_a: #Inner is not iterable
            print(e.to_string())

    class Inner(Enum):
        A = 1
        B = 2
        ALL = [A,B]
        NAMES = {A :"some_name_other_than_enum_a_name",
                 B :"some_name_other_than_enum_b_name"}

        def to_string(self):
             return Outer.Inner.NAMES[self.value]

if __name__ == '__main__':
    o = Outer()
    o.callInner()

Outer是具有所有逻辑的模块。类Inner是一个枚举,它包含枚举键值对A=1B=2以及所有可能枚举(或其中任何有趣的子集)的列表。其思想是建立一个列表,以便在这些列表上快速引用和迭代/枚举,而to-string可以是包含任何逻辑的arbritray方法。名称查找只是一个简化,以使问题变得清晰。


这里的问题不是您有一个内部类,而是内部类是一个Enum;但是,可以将非成员属性作为Enum类的一部分—有关详细信息,请参阅此问题和答案。

综上所述,您需要使用某种描述符使ALLNAMES,以避免将它们转换为枚举成员:

1
2
3
4
5
6
7
8
9
10
# inherit from `object` if using Python 2
class classattribute:   # was called Constant in the linked answer
    def __init__(self, value):
        self.value = value
    def __get__(self, *args):
        return self.value
    def __set__(self, _, value):
        self.value = value
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.value)

然后在你的电脑里1〔4〕:

1
2
3
4
5
    ALL = classattribute([A, B])
    NAMES = classattribute({
            A :"some_name_other_than_enum_a_name",
            B :"some_name_other_than_enum_b_name",
            })

这将避免您在callInner()方法中出现的错误,但会在print(e.to_string())行添加一个新的错误:

1
AttributeError: 'int' object has no attribute 'to_string'

其原因是构建Enum是一个由两部分组成的过程:

  • 收集所有定义:

    {
    'A':1,
    'B':2,
    'ALL':classattribute([A, B]),
    'NAMES':classattribute({'A':..., 'B':...}),
    'to_string':method(...),
    }

  • 将不是__dunder___sunder_descriptor的任何内容转换为枚举成员:

    • A->
    • B->

这意味着,在创建ALLNAMES时,AB仍然是int的,int没有to_string的方法。解决这个问题的简单方法是在尝试访问这些方法之前检索枚举成员:self.Inner(e).to_string()

要将它们组合在一起,您的代码应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# file Outer.py

from enum import Enum

class classattribute:
    def __init__(self, value):
        self.value = value
    def __get__(self, *args):
        return self.value
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.value)

class Outer:
    def callInner(self):
        all_a = Outer.Inner.ALL
        print(all_a)
        all_b = Outer.Inner.ALL[:]
        for e in all_a: #Inner is not iterable
            print(self.Inner(e).to_string())

    class Inner(Enum):
        A = 1
        B = 2
        ALL = classattribute([A,B])
        NAMES = classattribute(
                {A :"some_name_other_than_enum_a_name",
                 B :"some_name_other_than_enum_b_name"}
                )
        def to_string(self):
             return Outer.Inner.NAMES[self.value]

if __name__ == '__main__':
    o = Outer()
    o.callInner()

当跑步时,你会得到:

1
2
3
[1, 2]
some_name_other_than_enum_a_name
some_name_other_than_enum_b_name