【问题标题】:Subclassing a class with private members用私有成员子类化一个类
【发布时间】:2010-09-14 20:04:38
【问题描述】:
python 真正的优点之一是您可以简单地命名与访问器同名的变量:
self.__value = 1
def value():
return self.__value
是否有一种简单的方法可以访问我希望子类化的类的私有成员?通常我希望简单地处理类中的原始数据对象,而不必一直使用访问器和修改器。
我知道这似乎违背了私有和公共的一般概念,但通常我尝试子类化的类是我自己的类之一,我很乐意将成员从子类公开而不是实例那个班的。有没有一种干净的方式来提供这种区别?
【问题讨论】:
标签:
python
oop
encapsulation
【解决方案1】:
“我知道这似乎违背了私有和公共的一般概念”并不是真正的“反对”,只是与 C++ 和 Java 不同。
私有——在 C++ 和 Java 中实现并不是一个非常有用的概念。有时,它有助于隔离实现细节。但它被过度使用了。
以两个__ 开头的Python 名称是特殊的,通常情况下,您不应该用这样的名称定义属性。带有__ 的名称是特殊的并且是实现的一部分。并公开供您使用。
以_ 开头的名称是“私有的”。有时它们是隐蔽的,一点点。大多数情况下,“同意的成年人”规则适用——不要愚蠢地使用它们,它们可能会在没有通知的情况下更改。
我们将“私人”放在引号中,因为这只是您和您的用户之间的协议。你已经用_ 标记了一些东西。您的用户(和您自己)应该尊重这一点。
通常,我们的方法函数名称带有前导 _ 以表明我们认为它们是“私有的”并且可能会在不通知的情况下进行更改。
Java 所需的无穷无尽的 getter 和 setter 在 Python 中并不常用。 Python 自省更灵活,您可以访问对象的内部属性值字典,并且您拥有一流的functions,例如getattr() 和setattr()。
此外,您还有 property() 函数,它通常用于将 getter 和 setter 绑定到一个行为类似于简单属性但实际上是定义良好的方法函数调用的单个名称。
【解决方案2】:
不知道从哪里引用它,但以下关于访问保护的声明是 Pythonic 经典:“我们在这里都是同意的成年人”。
正如 Thomas Wouters 所说,单个前导下划线是将属性标记为对象内部状态的一部分的惯用方式。两个下划线只是提供名称修饰以防止轻松访问该属性。
在那之后,您应该期望您的图书馆的客户不会通过干预“私人”属性而自取其辱。
【解决方案3】:
不方便,没有进一步破坏封装。双下划线属性通过在要访问的类前面加上“_ClassName”来进行名称修改。因此,如果您有一个具有“__value”属性的“ContainerThing”类,则该属性实际上存储为“@ 987654321@'。更改类名(或重构分配属性的位置)将意味着破坏所有尝试访问该属性的子类。
这正是为什么双下划线名称修饰(这不是真正的“私人”,只是“不方便”)是一个不好的主意。只需使用 单个 前导下划线。每个人都知道不要触摸您的“私有”属性,您仍然可以在子类和其他方便的情况下访问它。双下划线属性的名称修饰仅用于避免真正特定于特定类的属性的名称冲突,这种情况极为罕见。它没有提供额外的“安全性”,因为即使是名称损坏的属性也可以轻松访问。
为了记录,“__value”和“value”(和“_value”)不是同一个名称。下划线是名称的一部分。