Python:从内部类访问外部私有函数

amk*_*ist 2 python inheritance private class function

我错过了什么,或者这样的事情不可能吗?

class Outer:
    def __init__(self, val):
        self.__val = val

    def __getVal(self):
        return self.__val

    def getInner(self):
        return self.Inner(self)

    class Inner:
        def __init__(self, outer):
            self.__outer = outer            

        def getVal(self):
            return self.__outer.__getVal()


foo = Outer('foo')
inner = foo.getInner()
val = inner.getVal()    
print val
Run Code Online (Sandbox Code Playgroud)

我收到此错误消息:

    return self.__outer.__getVal()
AttributeError: Outer instance has no attribute '_Inner__getVal'
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 8

您正在尝试将Java技术应用于Python类.别.Python没有像Java那样的隐私模型.即使在类中使用双下划线名称(它们只是重命名为添加命名空间),也始终可以访问类及其实例上的所有属性.__name

因此,您也不需要内部类,因为这样的类没有特权访问权限.您可以将该课程放在外面, Outer并具有完全相同的访问级别.

您遇到了错误,因为Python 在类上下文中使用初始双下划线名称重命名属性,以避免与子类发生冲突.这些被称为类私有,因为重命名将类名称添加为命名空间; 这适用于它们的定义和使用.请参阅参考文档的保留类标识符部分:

__*
类私有名称.当在类定义的上下文中使用时,此类别中的名称将被重写以使用损坏的表单来帮助避免基类和派生类的"私有"属性之间的名称冲突.

所有带有双下划线的名称都Outer被重命名为_Outer前缀,因此__getVal重命名为_Outer__getVal.任何此类名称都会发生相同的情况Inner,因此您的Inner.getVal()方法将查找_Inner__getVal属性.由于Outer没有_Inner__getVal属性,您会收到错误消息.

您可以手动应用相同的转换Inner.getVal()来"修复"此错误:

def getVal(self):
    return self.__outer._Outer__getVal()
Run Code Online (Sandbox Code Playgroud)

但是你并没有按照预期使用双下划线名称,所以转而使用单个下划线,并且不要使用嵌套类:

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()
Run Code Online (Sandbox Code Playgroud)

我重命名Inner_Inner文档类型是内部实现细节.

虽然我们在这个主题上,但实际上也没有必要使用访问器.在Python中,你可以切换property对象和普通属性在任何时候.没有必要在Java中进行防御性编码,在Java中,属性和访问器之间的切换会带来巨大的转换成本.在Python中,不要使用obj.getAttribute()obj.setAttribute(val)方法.只需使用obj.attributeobj.attribute = val,property如果您需要做更多工作来生成或设置值,请使用.property在开发周期中随意切换到或远离对象.

因此,您可以进一步简化以上内容:

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
Run Code Online (Sandbox Code Playgroud)

这里根据需要outer.inner生成一个新_Inner()实例,该Inner.val属性代理存储的self._outer引用.实例的用户永远不需要知道任何属性是由property对象处理的:

>>> outer = Outer(42)
>>> print outer.inner.val
42
Run Code Online (Sandbox Code Playgroud)

请注意,要property在Python 2中正常工作,必须使用新式类 ; 继承object来做这件事; property支持getter 上的旧式类(意味着设置也不会被阻止!).这是Python 3中的默认值.