Python 类没有公共(public)/私有(private)的概念,所以我们被告知不要触摸以下划线开头的东西,除非我们创建它。但这不需要我们直接或间接继承的所有类的完整知识吗?证人:
class Base(object):
def __init__(self):
super(Base, self).__init__()
self._foo = 0
def foo(self):
return self._foo + 1
class Sub(Base):
def __init__(self):
super(Sub, self).__init__()
self._foo = None
Sub().foo()
预计,TypeError
在评估 None + 1
时引发。所以我必须知道 _foo
存在于基类中。为了解决这个问题,可以改用 __foo
,它通过修改名称来解决问题。这似乎是一个可以接受的解决方案,即使不是很优雅。但是,如果 Base
继承自一个名为 Sub
的类(在单独的包中)会怎样?现在,我的 Sub
中的 __foo
覆盖了祖 parent Sub
中的 __foo
。
这意味着我必须知道整个继承链,包括每个使用的所有“私有(private)”对象。 Python 是动态类型的这一事实使这变得更加困难,因为没有要搜索的声明。然而,最糟糕的部分可能是 Base
现在可能从 object
继承,但在将来的某个版本中,它会切换到从 Sub
继承>。很明显,如果我知道 Sub
是从继承而来的,我就可以重命名我的类,尽管这很烦人。但我看不到 future 。
这不是真正的私有(private)数据类型可以防止出现问题的情况吗?在 Python 中,如果某人的脚趾可能会在未来某个时刻突然出现,我如何确定我不会不小心踩到他们的脚趾?
编辑:我显然没有说清楚主要问题。我熟悉名称修饰以及单下划线和双下划线之间的区别。问题是:我如何处理我可能会与 我现在不知道其存在 的类发生冲突的事实?如果我的父类(在我没有编写的包中)碰巧开始继承与我的类同名的类,那么即使名称修改也无济于事。将此视为真正的私有(private)成员可以解决但 Python 遇到麻烦的(角落)案例,我错了吗?
编辑:根据要求,以下是一个完整示例:
文件parent.py
:
class Sub(object):
def __init__(self):
self.__foo = 12
def foo(self):
return self.__foo + 1
class Base(Sub):
pass
文件 sub.py
:
import parent
class Sub(parent.Base):
def __init__(self):
super(Sub, self).__init__()
self.__foo = None
Sub().foo()
调用了祖 parent 的foo
,但使用了我的__foo
。
显然您不会自己编写这样的代码,但是 parent
可以很容易地由第三方提供,其细节可能随时更改。
最佳答案
使用private names (而不是 protected ),以双下划线开头:
class Sub(Base):
def __init__(self):
super(Sub, self).__init__()
self.__foo = None
# ^^
不会与 Base
中的 _foo
或 __foo
冲突。这是因为 Python 将双下划线替换为单下划线和类名;下面两行是等价的:
class Sub(Base):
def x(self):
self.__foo = None # .. is the same as ..
self._Sub__foo = None
(响应编辑:)类层次结构中的两个类不仅具有相同的名称,而且它们都使用相同的属性名称,并且都使用私有(private)损坏的机会(__
) 形式是如此之小,以至于在实践中可以安全地忽略它(到目前为止,我还没有听说过一个案例)。
但是,从理论上讲,您是正确的,因为为了正式验证程序的正确性,大多数人都知道整个继承链。幸运的是,在任何情况下,形式验证通常都需要一组固定的库。
这符合 Zen of Python 的精神, 其中包括
practicality beats purity.
关于python - Python 是否需要深入了解继承链中的所有类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11639722/