Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-property从抽象类继承时返回旧值_Python_Python 3.x - Fatal编程技术网

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成员有一个有效的用例。”(也就是说,为了避免名称与子类定义的名称发生名称冲突),对这种机制的支持是有限的,称为名称混乱。”使用的术语是名称混乱。