Python是否需要对继承链中所有类的深入了解?

Chr*_*ris 7 python private subclass

Python类没有公共/私有的概念,因此我们被告知不要触摸以下划线开头的东西,除非我们创建它.但是,这不需要直接或间接地完全了解我们继承的所有类吗?见证人:

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()
Run Code Online (Sandbox Code Playgroud)

预计TypeError会在None + 1评估时提高.所以我必须知道_foo基类中存在的东西.为了解决这个问题,__foo可以使用它,通过修改名称来解决问题.这似乎是一种可接受的解决方案,如果不是优雅的话.但是,如果Base从类(在单独的包中)继承,会发生什么Sub?现在__foo,我在祖父母的Sub覆盖.__fooSub

这意味着我必须知道整个继承链,包括每个使用的所有"私有"对象.Python是动态类型的这一事实使得这更加困难,因为没有要搜索的声明.然而,最糟糕的部分可能是现在Base可能继承的事实object,但在未来的某个版本中,它会转而继承Sub.显然,如果我知道Sub是继承自的,我可以重命名我的课程,无论多么烦人.但我看不到未来.

这不是真正的私有数据类型可以防止出现问题的情况吗?在Python中,如果这些脚趾可能会在未来的某个时刻出现,我怎么能确定我不会不小心踩到某个人的脚趾?

编辑:我显然没有明确主要问题.我熟悉名称修改以及单下划线和双下划线之间的区别.问题是:我如何处理这样一个事实,即我可能会碰到现在我不知道的类?如果我的父类(在我没有编写的包中)恰好从一个与我的类同名的类继承,那么名称修改也无济于事.我认为这是一个真正的私人成员会解决的(角落)案例,但是Python有问题吗?

编辑:根据要求,以下是一个完整的例子:

档案parent.py:

class Sub(object):
    def __init__(self):
        self.__foo = 12
    def foo(self):
        return self.__foo + 1
class Base(Sub):
    pass
Run Code Online (Sandbox Code Playgroud)

档案sub.py:

import parent
class Sub(parent.Base):
    def __init__(self):
        super(Sub, self).__init__()
        self.__foo = None
Sub().foo()
Run Code Online (Sandbox Code Playgroud)

祖父母foo被称为,但我__foo被使用了.

显然你不会自己编写这样的代码,但parent可以很容易地由第三方提供,其细节可能随时改变.

phi*_*hag 7

使用私有名称(而不是受保护名称),以双下划线开头:

class Sub(Base):
    def __init__(self):
        super(Sub, self).__init__()
        self.__foo = None
        #    ^^
Run Code Online (Sandbox Code Playgroud)

会不会产生冲突_foo__fooBase.这是因为Python用单个下划线和类的名称替换双下划线; 以下两行是等效的:

class Sub(Base):
    def x(self):
        self.__foo = None # .. is the same as ..
        self._Sub__foo = None
Run Code Online (Sandbox Code Playgroud)

(响应编辑:)类层次结构中的两个类不仅具有相同的名称,而且它们都使用相同的属性名,并且都使用私有的mangled(__)形式的可能性非常小,以至于它在实践中可以安全地忽略(到目前为止我还没有听说过一个案例).

然而,从理论上讲,你是正确的,为了正式验证程序的正确性,人们最了解整个继承链.幸运的是,正式验证通常需要一组固定的库.

这是禅宗的精神,包括

实用性胜过纯洁.


Eth*_*man 2

这意味着我必须了解整个继承链。。。

是的,您应该了解整个继承链,或者您直接子类化的对象的文档应该告诉您需要了解的内容。

子类化是一项高级功能,应谨慎对待。

指定子类中应重写的内容的一个很好的文档示例是线程类

此类表示在单独的控制线程中运行的活动。有两种方法可以指定活动:将可调用对象传递给构造函数,或者重写run()子类中的方法。子类中不应重写其他方法(构造函数除外)。换句话说,只重写该类的__init__()和方法。run()