The issue here is not that you have an inner class, but that the inner class is an Enum
; however, it is possible to have non-member attributes as part of an Enum
class -- see this question and answer for the details.
To summarize, you need to make ALL
and NAMES
with some kind of descriptor to avoid having them transformed into enum members:
# 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)
and then in your Inner
:
ALL = classattribute([A, B])
NAMES = classattribute({
A : "some_name_other_than_enum_a_name",
B : "some_name_other_than_enum_b_name",
})
This will avoid the errors you are getting in your callInner()
method, but will add a new one at the print(e.to_string())
line:
AttributeError: 'int' object has no attribute 'to_string'
The reason for this is that constructing an Enum
is a two-part process:
gather all the definitions:
{
'A':1,
'B':2,
'ALL':classattribute([A, B]),
'NAMES':classattribute({'A':..., 'B':...}),
'to_string':method(...),
}
transform anything not a __dunder__
, _sunder_
, nor descriptor
into an enum member:
A
-> <Inner.A: 1>
B
-> <Inner.B: 2>
What this means is that when ALL
and NAMES
were being created, A
and B
were still int
s, and int
s don't have a to_string
method. The easy way around that is to retrieve the enum member before trying to access those methods: self.Inner(e).to_string()
.
To pull it all together, here is what your code should look like:
# 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()
and when run, this is what you get:
[1, 2]
some_name_other_than_enum_a_name
some_name_other_than_enum_b_name