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

ulo*_*oco 58 python methods inheritance private protected

我知道,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'
Run Code Online (Sandbox Code Playgroud)

那么,这种行为是否意味着,"受保护"方法将被继承,但"私有"根本不会被继承?
或者我错过了什么?

Mar*_*ers 86

Python没有隐私模型,没有像C++,C#或Java那样的访问修饰符.没有真正的"受保护"或"私人"属性.

具有前导双下划线且没有尾随双下划线的名称会受到损坏,以保护它们在继承时不会发生冲突.子类可以定义自己的__private()方法,这些方法不会干扰父类的相同名称.这些名称被视为私人 ; 他们仍然可以从课外进入,但不太可能发生意外冲突.

Mangling是通过在任何此类名称前加上额外的下划线和类名(无论名称如何使用或是否存在)来完成的,从而有效地为它们提供了命名空间.在Parent类中,任何__private标识符都由名称替换(在编译时)_Parent__private,而在Child类中,标识符将替换_Child__private为类定义中的任何位置.

以下将有效:

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

    def bar(self):
        self._Parent__private()
Run Code Online (Sandbox Code Playgroud)

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

__*
类私有名称.当在类定义的上下文中使用时,此类别中的名称将被重写以使用损坏的表单来帮助避免基类和派生类的"私有"属性之间的名称冲突.

以及关于名称的引用文档:

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

不要使用类私有名称,除非您特别希望避免告诉开发人员想要将您的类子类化为不能使用某些名称或冒险破坏您的类.在已发布的框架和库之外,此功能几乎没有用处.

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

如果您的类要进行子类化,并且您具有不希望使用子类的属性,请考虑使用双前导下划线和没有尾随下划线来命名它们.这将调用Python的名称修改算法,其中类的名称被修改为属性名称.如果子类无意中包含具有相同名称的属性,这有助于避免属性名称冲突.

注1:请注意,在修改的名称中只使用简单的类名,因此如果子类同时选择相同的类名和属性名,则仍然可以获得名称冲突.

注意2:名称修改可以进行某些用途,例如调试 __getattr__(),不太方便.但是,名称修改算法已有详细记录,并且易于手动执行.

注3:不是每个人都喜欢名字错误.尽量平衡避免意外姓名冲突与高级呼叫者潜在使用的需要.


Tim*_*der 12

double __属性被更改为_ClassName__method_name使其比隐含的语义隐私更私密_method_name.

如果你真的愿意,你在技术上仍然可以得到它,但可能没有人会这样做,所以为了维护代码抽象的原因,这个方法在那时也可能是私有的.

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

    def __private(self):
        print("Is it really private?")

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

    def bar(self):
        self.__private()

c = Child()
c._Parent__private()
Run Code Online (Sandbox Code Playgroud)

这具有允许方法不与子类方法名称冲突的额外优势(或者一些可以说是主要优势).

  • 如果在 Child 内部使用 Parent 私有方法进行调用,则这不起作用 (3认同)

Kob*_*i K 10

通过声明您的数据成员 private :

__private()

你根本无法从课堂外访问它

Python 支持一种名为name mangling的技术。

此功能将带有两个下划线前缀的类成员转换为:

_className.memberName

如果你想访问它,Child()你可以使用:self._Parent__private()


Dec*_*eck 7

此外PEP8

仅对非公共方法和实例变量使用一个前导下划线.

为避免与子类发生名称冲突,请使用两个前导下划线来调用Python的名称修改规则.

Python使用类名来破坏这些名称:如果class Foo有一个名为的属性__a,则无法访问它Foo.__a.(一种连续不断的用户仍然可以通过调用获得Foo._Foo__a.)一般情况下,双领先下划线只应该用于避免名称冲突,在设计,被继承的类属性.

_such_methods按照惯例,你应该远离它.我的意思是你应该把它们视为private