【问题标题】:Getting parent private or protected values from the child class从子类获取父级私有或受保护值
【发布时间】:2014-12-06 18:27:51
【问题描述】:

嗯,我有几乎相同的question,除了一个细节:我需要获取基类的私有值。代码:

class Parent(object):
    def __init__(self):
        self.__field = 13    

class Child(Parent):
    """docstring for Child"""
    def __init__(self):
        super(Child, self).__init__()

    def ChildMethodWhichUsingParentField(self):
        return self.__field

if __name__ == '__main__':
    c = Child()
    c.ChildMethodWhichUsingParentField()

解释器输出:

Traceback (most recent call last):
  File "foo.py", line 20, in <module>
    c.ChildMethodWhichUsingParentField()
  File "foo.py", line 16, in ChildMethodWhichUsingParentField
    return self.__field
AttributeError: 'Child' object has no attribute '_Child__field'

问题是解释器在我需要_Parent__field 时尝试获取_Child__field。我可以使用@property 获得这个值,但它会破坏封装。我也可以写self._Parent__field 来解决这个问题,但这是丑陋且显然是糟糕的代码。还有其他方法吗?

【问题讨论】:

  • 为什么不停止在field 前加上两个下划线?
  • 单下划线是要走的路,用于自定义“私有”类成员。
  • @jonrsharpe,因为这会破坏封装。 field 很重要,仅供内部使用。我想确保没有人可以看到和/或修改field
  • @Montreal 这并没有做到这一点 - Python 没有私有属性,我们在这里都是同意的成年人。双下划线只是调用名称修饰,这不会阻止故意的外部访问并使必要的访问变得痛苦(正如您所经历的那样)。如果它应该被认为是私有的,一个下划线就足够了。名称修改只是为了避免冲突,请参阅legacy.python.org/dev/peps/pep-0008/#naming-conventions。 (此外,在这种情况下,它是 "break"。)
  • @jonrsharpe 我知道,但我对我最喜欢的语言的这一方面感到有点失望。

标签: python oop inheritance


【解决方案1】:

正如您在问题中所指出的,您可以通过在子类中显式使用其名称的错位形式来访问父属性:

def ChildMethodWhichUsingParentField(self):
    return self._Parent__field

这是您直接问题的唯一简单答案。

但是,如果您可以控制 Parent 类,这将是一个非常糟糕的设计。你不应该对另一个类类将使用的东西使用双下划线属性名称(实际上你可能不应该使用它,即使你不期望任何这样的用途)。请改用单个下划线 (_field)。这个“文件”表明该属性是私有的(例如,不是类的公共 API 的一部分),而不启用名称修改。这样,如果您发现晚于另一个类确实需要访问它可以的变量。 Python 不强制隐私(即使在使用名称修饰时也不强制),因此您总是需要依赖其他表现良好的代码。

名称修改实际上仅适用于需要避免名称冲突的情况。例如,代理对象可能对其自身的属性使用错位名称,以便它可以呈现一个与另一个对象的接口完全相同的接口(可能无法提前知道)。或者,mixin 类可能对其变量使用名称修饰,因为它无法确定将在(可能许多)其他将与其一起继承的类中使用哪些属性名称。如果您将自己使用的属性添加到其他对象(不是self)并希望避免错误地覆盖其现有属性,它也很有用。

【讨论】:

  • 是否有任何鼓励隐私的建议?恕我直言,这是非常大的python缺陷。甚至比低速还大。
  • @Montreal:Python 开发者社区并不认为缺乏隐私保护是一个缺陷。确实,这是一个特点。如果你真的需要,你可以进去修改任何东西。当事情没有按预期进行时,这非常有用,并且您想将日志记录注入现有类,或者自省某些东西以调试奇怪的行为。
【解决方案2】:

这可以通过添加一个 getter 来实现

class Parent(object):
    def __init__(self):
        self.__field = 13  

    def get_field(self):
        return self.__field

class Child(Parent):
    """docstring for Child"""
    def __init__(self):
        super(Child, self).__init__()


    def ChildMethodWhichUsingParentField(self):
        return self.get_field()

if __name__ == '__main__':
    c = Child()
    print c.ChildMethodWhichUsingParentField()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-15
    • 2012-06-22
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多