我知道,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'
那么,这种行为是否意味着“受保护”的方法将被继承,但“私有”的方法将不会被继承呢?
还是我错过了什么?
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:并非每个人都喜欢名称修饰。尝试在避免意外名称冲突和高级呼叫者可能使用名称之间取得平衡。
我知道,这与名称修改有关。我知道我可以通过_Parent__private从类外部访问该方法,但是我不明白为什么不能在继承的类中调用它。我不知道,子类有自己的功能
__private()
,非常感谢您的明确回答!怎么样
__getstate__()
和__setstate__()
?一个孩子将无法从其父母那里继承这些方法?@BoltzmannBrain:这些名称也在末尾包含下划线,而不仅仅是名称的开头。那是另一类名字。请参阅我链接到的文档。
谢谢,但是那里的文档并没有给我更多有用的信息。我已经将其移至另一个问题:stackoverflow.com/questions/44444733/…
@Martijn:谢谢你的回答。
pythonic style
尝试将所有变量设为一个类内部的私有变量,然后将getters
和setters
用于这些私有变量时,也许我没有使用a 。好吧,我应该在Google上查询有关私有变量用法的问题。