Python-property从抽象类继承时返回旧值
我的问题是关于继承的类解析顺序。这是一个虚拟代码片段,说明了我的问题:Python-property从抽象类继承时返回旧值,python,python-3.x,Python,Python 3.x,我的问题是关于继承的类解析顺序。这是一个虚拟代码片段,说明了我的问题: from abc import ABC, abstractmethod class BaseClass(ABC): def __init__(self): self.__value = 1 self.set_value() @abstractmethod def set_value(self): raise NotImplementedError
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.__value = 1
self.set_value()
@abstractmethod
def set_value(self):
raise NotImplementedError
@property
def value(self):
return self.__value
class DerivedClass(BaseClass):
def __init__(self):
super().__init__()
def set_value(self):
self.__value = 2
dc = DerivedClass()
print(dc._DerivedClass__value)
print(dc.value)
assert dc.value == 2
代码输出:
2
1
Traceback (most recent call last):
File "<stdin>", line 26, in <module>
AssertionError
2
1.
回溯(最近一次呼叫最后一次):
文件“”,第26行,在
断言错误
我希望DerivedClass
在\uuuuu init\uuuu
中调用set\u value
方法之前覆盖该方法。但是,情况并非如此,因为属性以某种方式记住了原始的\u值
值,而不是新值。有人能解释一下为什么会这样吗
在这种情况下,什么是好的解决方案?我的实际情况是一个相当大的基类,继承的类只覆盖关键方法,比如
.set\u value
。,因为您使用了双下划线名称混乱,self.\u value
。这将防止子类能够重写\uu值
,这是它的唯一目的
如果要修复它,请使用传统的单下划线:
self._value
我希望DerivedClass
在\uuuuu init\uuuu
中调用set\u value
方法之前覆盖该方法
是的,这确实发生了。构造函数中调用的set\u value()
是来自DerivedClass
的
情况并非如此,因为属性不知何故记住了原始的\u值
值,而不是新值
不,这里发生的是有两个独立的变量。尽管两者的名称相同(\uu value
),但它们实际上是不同的、独立的变量
这就是Python中私有变量(以两个下划线开头,以少于两个下划线结尾的变量)的行为方式
实现的方式是Python会破坏它们的名称。事实上,在第一个print()
语句中,您自己正在利用这一点,查看\u DerivedClass\u值
您可以在脑海中重写此代码,从基类
中的代码中所有对基类
的引用实际上都读取了\u基类
并且您将清楚地看到发生了什么
由于value
属性是在BaseClass
中定义的,因此它将始终返回\u BaseClass\u值
您正在DerivedClass
上设置\u DerivedClass\u值,但无法访问它
在这种情况下,什么是好的解决方案
不要使用私有变量。他们倾向于制造这种混乱。改为使用受保护的变量,例如self.\u value
,因为它们可以从派生类中很好地访问(没有名称损坏)
如果您不能做到这一点,那么假设您不能从子类中访问私有变量(因为实际上,您实际上不能!),并在本例中通过公开的访问器,例如set、\u value()
如果您想修改子类中set_value()
方法的行为,那么当您想设置实际值时,使用super()
来访问基类的实现(因为写入self.\u value
不会工作,正如您所注意到的那样)。@George。但是你应该问问自己,为什么你首先要使用双下划线的名称。它与private不同,python没有私有变量。不要像在Java中那样随意使用它。它特别用于防止子类中的意外名称冲突。python没有私有变量。@juanpa.arrivillaga我同意它们不是真正私有的,只是名称冲突。但是你可以在C++中这样做,如果你知道该怎么做,你可以用指针操作访问一个私有成员…在任何情况下,“private variable”是Python本身使用的术语,我看不出有任何理由不遵循它。不,从您自己的链接:“private”实例变量在Python中不存在,除非从对象内部访问,否则无法访问。“因为类private成员有一个有效的用例。”(也就是说,为了避免名称与子类定义的名称发生名称冲突),对这种机制的支持是有限的,称为名称混乱。”使用的术语是名称混乱。