You are trying to apply Java techniques to Python classes. Don't. Python has no privacy model like Java does. All attributes on a class and its instances are always accessible, even when using __name
double-underscore names in a class (they are simply renamed to add a namespace).
As such, you don't need an inner class either, as there is no privileged access for such a class. You can just put that class outside Outer
and have the exact same access levels.
You run into your error because Python renames attributes with initial double-underscore names within a class context to avoid clashing with subclasses. These are called class private because the renaming adds the class names as a namespace; this applies both to their definition and use. See the Reserved classes of identifiers section of the reference documentation:
__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.
All names with double underscores in Outer
get renamed to _Outer
prefixed, so __getVal
is renamed to _Outer__getVal
. The same happens to any such names in Inner
, so your Inner.getVal()
method will be looking for a _Inner__getVal
attribute. Since Outer
has no _Inner__getVal
attribute, you get your error.
You could manually apply the same transformation to Inner.getVal()
to 'fix' this error:
def getVal(self):
return self.__outer._Outer__getVal()
But you are not using double-underscore names as intended anyway, so move to single underscores instead, and don't use a nested class:
class Outer:
def __init__(self, val):
self._val = val
def _getVal(self):
return self._val
def getInner(self):
return _Inner(self)
class _Inner:
def __init__(self, outer):
self._outer = outer
def getVal(self):
return self._outer._getVal()
I renamed Inner
to _Inner
to document the type is an internal implementation detail.
While we are on the subject, there really is no need to use accessors either. In Python you can switch between property
objects and plain attributes at any time. There is no need to code defensively like you have to in Java, where switching between attributes and accessors carries a huge switching cost. In Python, don't use obj.getAttribute()
and obj.setAttribute(val)
methods. Just use obj.attribute
and obj.attribute = val
, and use property
if you need to do more work to produce or set the value. Switch to or away from property
objects at will during your development cycles.
As such, you can simplify the above further to:
class Outer(object):
def __init__(self, val):
self._val = val
@property
def inner(self):
return _Inner(self)
class _Inner(object):
def __init__(self, outer):
self._outer = outer
@property
def val(self):
return self._outer._val
Here outer.inner
produces a new _Inner()
instance as needed, and the Inner.val
property proxies to the stored self._outer
reference. The user of the instance never need know either attribute is handled by a property
object:
>>> outer = Outer(42)
>>> print outer.inner.val
42
Note that for property
to work properly in Python 2, you must use new-style classes; inherit from object
to do this; on old-style classes on property
getters are supported (meaning setting is not prevented either!). This is the default in Python 3.