我试图让一个子类从一些父类继承一个指向父亲自己的私有变量的方法。我希望子项的继承方法使用子级自己的私有变量。如果不重新定义子类中的整个方法,这可能吗?
如果使用公共或受保护(单个下划线)变量,代码可以正常工作。但是我们的教练坚持使用私有(双下划线)变量。我们只有几天的面向对象编程,所以我真的不知道我在寻找什么术语(对不起!)。
我怀疑我应该只使用受保护的,但我希望尽可能遵守说明。
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
的method1
使用ClassB
的__var
(_ClassB__var
)。
我可以让ClassB
有一个名为_ClassA__var
的变量并将其设置为20
,它确实有效,但这是一种混乱的IMO。
编辑:我想我找到了答案。
class ClassA:
def __init__(self): self.__var = 10
def method1(self): return self.get_var() + 1
def get_var(self): return self.__var
def set_var(self, val): self.__var = val
class ClassB(ClassA):
def __init__(self): self.__var = 20
def get_var(self): return self.__var
def set_var(self, val): self.__var = val
ObjectA = ClassA()
ObjectB = ClassB()
print(ObjectA.method1())
print(ObjectB.method1())
我没有直接引用类属性,而是将方法指向了getter。这个想法来自这篇文章的评论。在编辑时,它没有包含在答案中,所以为了清楚起见,我将它放在这里。
谢谢,@ Allan!
让ClassB
使用ClassA
的__var
而不侵入其命名空间是不可能的。正如您所注意到的,当您使用__var
时,Python解释器实际上将变量重命名为_classname__variable
。这包括在method1
中的引用,所以现在method1
将始终引用__var
中的ClassA
。如果你真的想要一些疯狂的解决方案,它可能是可能的,但我认为你的教练不会喜欢它,因为你会非常违反封装。
在Java等其他语言中,您实际上有三种访问级别:私有,受保护和公共访问。私有意味着只有同一个类的对象才能查看和操作它。受保护就是你所追求的,Python在语言中没有。你可以得到的最接近的是使用_var
,这是一个Python惯例,而不是规则。事实上,对于大多数真实世界的生产Python代码,单个下划线就足够了,因为它向其他程序员表明“不要乱用这个属性”。对于公共属性,只需在没有前面下划线的情况下命名变量。
现在,Python中确实没有私有属性/变量。有关self._var
和self.__var
之间差异的更多信息,请参阅此主题:What is the meaning of a single and a double underscore before an object name?
如果你想用method1
的ClassB
在ClassA
对象中调用__var
,你需要首先在ClassA
的构造函数中初始化ClassB
的构造函数(假设Python 3在这里):
class ClassB(ClassA):
def __init__(self):
super().__init__()
self.__var = 20
当您通过super().__init__()
调用该构造函数时,您实际上是在内存中初始化ClassA
的属性。如果你不这样做,它将不会初始化任何东西,因此你得到那个AttributeError
。
这是让它工作的一种肮脏方式。请不要在作业中这样做。事实上,除非你有充分的理由这样做,否则不要在任何代码中执行此操作:
class ClassA:
def __init__(self):
self.__var = 10
def method1(self):
varname = "_{}__var".format(self.__class__.__name__)
v = getattr(self, varname)
setattr(self, varname, v + 1)
return getattr(self, varname)
class ClassB(ClassA):
def __init__(self):
super().__init__()
self.__var = 20