Python 3.5 内部 class(enum) 中 static/class lists/dictionaries 的初始化
Initialization of static/class lists/dictionaries in inner class(enum) in Python 3.5
是否可以像其他变量一样在内部枚举 class 中初始化 static/class 字典?
# 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()
class Outer
是包含所有逻辑的模块。 class Inner
是一个枚举,它确实包含枚举键值对 A=1
和 B=2
以及所有可能的枚举列表(或其任何有趣的子集) .这个想法是有一个列表供快速参考和 iteration/enumeration 在那些之上,而 to_string 可以是包含任何逻辑的任意方法。名称查找只是为了使问题更清楚的简化。
这里的问题不是你有一个内部 class,而是内部 class 是一个 Enum
;但是,可以将非成员属性作为 Enum
class 的一部分——有关详细信息,请参阅 this question and answer。
总而言之,您需要使用某种描述符来制作 ALL
和 NAMES
,以避免将它们转换为枚举成员:
# 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)
然后在你的 Inner
:
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())
行添加一个新错误:
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
-> <Inner.A: 1>
B
-> <Inner.B: 2>
这意味着在创建 ALL
和 NAMES
时,A
和 B
仍然是 int
,而 int
s 没有 to_string
方法。解决这个问题的简单方法是在尝试访问这些方法之前检索枚举成员:self.Inner(e).to_string()
.
为了将它们组合在一起,您的代码应该如下所示:
# 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]
some_name_other_than_enum_a_name
some_name_other_than_enum_b_name
是否可以像其他变量一样在内部枚举 class 中初始化 static/class 字典?
# 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()
class Outer
是包含所有逻辑的模块。 class Inner
是一个枚举,它确实包含枚举键值对 A=1
和 B=2
以及所有可能的枚举列表(或其任何有趣的子集) .这个想法是有一个列表供快速参考和 iteration/enumeration 在那些之上,而 to_string 可以是包含任何逻辑的任意方法。名称查找只是为了使问题更清楚的简化。
这里的问题不是你有一个内部 class,而是内部 class 是一个 Enum
;但是,可以将非成员属性作为 Enum
class 的一部分——有关详细信息,请参阅 this question and answer。
总而言之,您需要使用某种描述符来制作 ALL
和 NAMES
,以避免将它们转换为枚举成员:
# 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)
然后在你的 Inner
:
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())
行添加一个新错误:
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
-><Inner.A: 1>
B
-><Inner.B: 2>
这意味着在创建 ALL
和 NAMES
时,A
和 B
仍然是 int
,而 int
s 没有 to_string
方法。解决这个问题的简单方法是在尝试访问这些方法之前检索枚举成员:self.Inner(e).to_string()
.
为了将它们组合在一起,您的代码应该如下所示:
# 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]
some_name_other_than_enum_a_name
some_name_other_than_enum_b_name