Warm tip: This article is reproduced from serverfault.com, please click

其他-Python中私有方法和受保护方法的继承

(其他 - Inheritance of private and protected methods in Python)

发布于 2013-11-28 08:54:36

我知道,Python中没有“真正的”私有/受保护的方法。这种方法并不意味着要隐藏任何东西。我只想了解Python的功能。

class Parent(object):
    def _protected(self):
        pass

    def __private(self):
        pass

class Child(Parent):
    def foo(self):
        self._protected()   # This works

    def bar(self):
        self.__private()    # This doesn't work, I get a AttributeError:
                            # 'Child' object has no attribute '_Child__private'

那么,这种行为是否意味着“受保护”的方法将被继承,但“私有”的方法将不会被继承呢?
还是我错过了什么?

Questioner
uloco
Viewed
11
2017-12-19 02:22:26

Python没有隐私模型,没有像C ++,C#或Java这样的访问修饰符。没有真正的“受保护”或“私有”属性。

带有前导双下划线但不带尾部双下划线的名称将被重编,以保护它们在继承时不发生冲突。子类可以定义自己的__private()方法,并且不会干扰父类上的相同名称。这样的名字被认为是私有的; 他们仍然可以从班级外部访问,但是发生意外冲突的可能性要小得多。

通过在此类名称前添加一个额外的下划线和类名称(无论名称如何使用或是否存在),来进行改型,从而有效地为其命名空间Parent类中,任何__private标识符都将由name替换(在编译时)_Parent__private,而在Child类中_Child__private,在类定义中的任何地方,标识符均由替换

以下将起作用:

class Child(Parent):
    def foo(self):
        self._protected()

    def bar(self):
        self._Parent__private()

请参阅词法分析文档中的标识符的保留类

__*
类私有名称。当在类定义的上下文中使用时,此类别中的名称将被重写以使用变形的形式,以帮助避免基类和派生类的“私有”属性之间的名称冲突。

以及有关名称的参考文档

私有名称修饰:当在类定义中以文本形式出现的标识符以两个或多个下划线字符开头且不以两个或多个下划线结尾时,则被视为该类的私有名称。在为专用名称生成代码之前,专用名称会转换为更长的格式。转换将在类名之前插入类名,并删除前导下划线,并插入单个下划线。例如,__spam出现在名为Ham的类中的标识符将转换为_Ham__spam此转换独立于使用标识符的句法上下文。

不要使用类专用名称,除非你特别想要避免告诉那些想对你的类进行子类化的开发人员,他们不能使用某些名称或冒着破坏你的类的风险。在已发布的框架和库之外,此功能很少使用。

PEP 8 Python的风格指南是这样说的关于私有名字改编:

如果你的类打算被子类化,并且你具有不想使用子类的属性,请考虑使用双引号和下划线来命名它们。这将调用Python的名称修改算法,其中将类的名称修改为属性名称。这有助于避免属性名称冲突,如果子类无意中包含名称相同的属性。

注1:请注意,整齐的名称中仅使用简单的类名,因此,如果子类同时选择了相同的类名和属性名,则仍会发生名称冲突。

注意2:名称修饰可以使某些用途(例如调试和 __getattr__())变得不太方便。但是,名称修饰算法已被详细记录,并且易于手动执行。

注意3:并非每个人都喜欢名称修饰。尝试在避免意外名称冲突和高级呼叫者可能使用名称之间取得平衡。