提问人:Dan 提问时间:10/2/2008 更新时间:10/3/2008 访问量:2312
使用私有成员对类进行子类化
Subclassing a class with private members
问:
python 的一个真正好处是,你可以用它来命名与访问器同名的变量:
self.__value = 1
def value():
return self.__value
有没有一种简单的方法可以提供对我希望子类化的类的私有成员的访问?通常,我希望简单地使用类中的原始数据对象,而不必一直使用访问器和赋值器。
我知道这似乎违背了私有和公共的一般概念,但通常我试图子类的类是我自己的类之一,我很乐意将成员暴露给子类,而不是该类的实例。有没有一种干净的方法来提供这种区别?
答:
不方便,无需进一步破坏封装。双下划线属性通过为正在访问它的类前置“_ClassName”来命名。因此,如果您有一个具有“__value”属性的“ContainerThing”类,则该属性实际上被存储为“”。更改类名(或重构属性的分配位置)将意味着断开所有尝试访问该属性的子类。_ContainerThing__value
这就是为什么使用双下划线名称(不是真正的“私人”,只是“不方便”)是一个坏主意。只需使用一个前导下划线。每个人都会知道不要碰你的“私有”属性,你仍然可以在子类和其他方便的情况下访问它。双下划线属性的名称修改仅用于避免真正特定于特定类的属性的名称冲突,这种情况极为罕见。它没有提供额外的“安全性”,因为即使是名称受损的属性也很容易访问。
郑重声明,“”和“”(和“”)不是同一个名称。下划线是名称的一部分。__value
value
_value
不知道从哪里引用它,但以下关于访问保护的声明是 Pythonic 的经典:“我们在这里都是同意的成年人”。
正如 Thomas Wouters 所说,单个前导下划线是将属性标记为对象内部状态一部分的惯用方式。两个下划线仅提供名称修改,以防止轻松访问属性。
在那之后,你应该期望你的图书馆的客户不会通过干涉“私有”属性来搬起石头砸自己的脚。
“我知道这似乎违背了私有和公共的一般理念”并不是真正的“反对”,只是与C++和Java不同。
私有 - 在C++和Java中实现并不是一个非常有用的概念。有时,隔离实现细节会有所帮助。但它被过度使用。
以 2 开头的 Python 名称很特殊,作为正常情况,您不应该使用这样的名称来定义属性。带有 的名称是特殊的,并且是实现的一部分。并公开供您使用。__
__
以 1 开头的名称是“私人”的。有时它们被隐藏起来,有点。大多数时候,“同意的成年人”规则适用——不要愚蠢地使用它们,它们可能会发生变化,恕不另行通知。_
我们将“私人”放在引号中,因为它只是您和您的用户之间的协议。您已用 标记了 。你的用户(和你自己)应该尊重这一点。_
通常,我们的方法函数名称带有前导,以表明我们认为它们是“私有的”,如有更改,恕不另行通知。_
Java 需要的无穷无尽的 getter 和 setter 在 Python 中并不常用。Python 内省更加灵活,您可以访问对象的属性值内部字典,并且您拥有像 和 这样的第一类函数。getattr()
setattr()
此外,您有一个函数,该函数通常用于将 getter 和 setter 绑定到单个名称,该名称的行为类似于简单属性,但实际上是定义良好的方法函数调用。property()
下一个:版本化词典的接口
评论