我试图让一个子类从某个父类继承一个指向父辈自己的私有变量的方法。我希望孩子的继承方法使用孩子自己的私有变量。不必在子类中重新定义整个方法,这是否可能?
如果使用公共或受保护的(单个下划线)变量,则代码可以正常工作。但是我们的讲师坚持使用私有(双下划线)变量。我们只有几天才进行面向对象的编程,所以我真的不知道我要寻找的术语(抱歉!)。
我怀疑我应该只使用受保护的产品,但是我想尽可能地遵守说明。
class ClassA:
def __init__(self): self.__var = 10
def method1(self):
self.__var += 1 #method1 is intended to work on ClassA's __var
return self.__var #The method will also return the processed value of ClassA's __var
class ClassB(ClassA):
def __init__(self): self.__var = 20
#ClassA's method1 is inherited by ClassB.
#But I want this method1 to use ClassB's __var
ObjectA = ClassA()
ObjectB = ClassB()
print(ObjectA.method1()) #Will output 11
print(ObjectB.method1()) #Will raise an AttributeError, still looks for __var of ClassA
以上只是我打算实现的目标的一个证明。
使用公共或受保护的变量时,我将得到11
和21
的输出。
但是,当使用私有变量时,我将遇到一个11
和一个错误。
我希望ClassB
的{{1}}使用method1
的{{1}}(ClassB
)。
我可以让__var
拥有一个名为_ClassB__var
的变量并将其设置为ClassB
,它确实可以工作,但是这有点麻烦IMO。
编辑:我想我已经找到了答案。
_ClassA__var
我没有直接引用类属性,而是将方法指向吸气剂。这个想法来自这篇文章的评论。在进行此编辑时,它并未包含在答案中,因此为了清楚起见,将其放在此处。
谢谢@Allan!
答案 0 :(得分:3)
ClassB
使用ClassA
的{{1}}而不侵犯其名称空间是不可能的。如您所见,当您使用__var
时,Python解释器实际上将变量重命名为__var
之类。其中包括_classname__variable
中的引用,所以现在method1
将始终引用method1
中的__var
。如果您确实想要一些疯狂的解决方案,则可能是可能的,但是我认为您的教练会不喜欢它,因为您将非常违反封装。
在其他语言(如Java)中,您实际上具有三个访问级别:私有,受保护和公共。 Private (私人)表示只有相同类别的对象才能看到和操作它。 受保护的是您要追求的目标,而Python在该语言中没有。最接近的方法是使用ClassA
,这是Python约定,而不是规则。实际上,对于大多数现实世界的生产Python代码而言,一个下划线就足够了,因为它向其他程序员表明“不要弄乱此属性”。至于 public 属性,只需在变量前加上下划线即可。
现在,Python中确实没有私有属性/变量。有关_var
和self._var
之间的区别的更多信息,请参见此线程:What is the meaning of a single and a double underscore before an object name?
如果您想使用self.__var
的{{1}}在method1
对象中调用ClassB
,则需要首先初始化ClassA
的构造函数在__var
的构造函数中(此处使用Python 3):
ClassA
通过ClassB
调用该构造函数时,实际上是在初始化内存中的class ClassB(ClassA):
def __init__(self):
super().__init__()
self.__var = 20
的属性。如果不这样做,它将不会初始化任何内容,因此您会得到super().__init__()
。
这是使其工作的一种肮脏方式。请不要在您的作业中这样做。实际上,除非您有非常的充分理由,否则不要在任何代码中执行此操作:
ClassA