class Test1: def __init__( self ): self.__test = 1 def getvalue( self ): return self.__test class Test2( Test1 ): def __init__( self ): Test1.__init__( self ) self.__test = 2 test = Test2()
为什么打印test.getvalue()会返回1?
答案 0 :(得分:9)
在Python中,类__bar
的私有成员Foo
将为automatically renamed到_Foo__bar
,因此__test
中的Test1
为{{ 1}}和_Test1__test
中的Test2
是_Test2__test
。这两个成员实际上是不同的。这是按设计,到"avoid name clashes of names with names defined by subclasses"。
如果您希望子类看到变量,同时仍希望它不是公共接口的一部分,请使用单个下划线_test
。
答案 1 :(得分:6)
此行为是由name mangling for attribute names starting with __
引起的。基本上,__test
在_Test1__test
内变为Test1
,在_Test2__test
内变为Test2
,因此它们是两个不同的属性。
答案 2 :(得分:1)
它在其他语言中的工作方式完全相同,例如Java(试一试!)
class Test1 {
private int test = 1;
public int getValue() {
return test;
}
}
class Test2 extends Test1 {
private int test = 2;
}
public class Test { // Run the test
public static void main(String[] args) {
Test2 t = new Test2();
System.out.println(t.getValue());
}
}
(为什么我在Python相关问题中发布Java代码?因为有些评论说“这不适用于任何OO语言”和“这就是为什么你不使用名称修改为私有变量“ - 与Python相比,Java采用另一种方法来处理OO,并且不对私有变量使用名称修改,但行为是相同的)
Test1中声明的方法可以访问Test1的私有变量。除非子类重写该方法,否则从子类调用该方法不会更改任何内容。这并不是私人成员在子类中“消失”或“被覆盖”。它们仍然存在,可以通过父类的方法访问。
只有当Test2为getvalue()声明自己的实现时,Test1的私有成员才会变得不可访问,并且Test2的私有成员将变得可访问。
换句话说,可以说私人成员不是“虚拟的”(或“可覆盖的”)。它们是类及其方法的实现细节,不应该被覆盖。 Test1.__test
和Test2.__test
是不同的实例变量(通过名称修改在Python中实现)。
如果您想要传统的OO行为,其中子类成员会覆盖其父类,请在C ++中使用Python,Java或虚方法中的方法,C# ,德尔福; 不 私有属性。如果你想实现没有名字冲突的东西,那么使用私有属性。