返回介绍

9.7 Python 的私有属性和“受保护的”属性

发布于 2024-02-05 21:59:47 字数 2454 浏览 0 评论 0 收藏 0

Python 不能像 Java 那样使用 private 修饰符创建私有属性,但是 Python 有个简单的机制,能避免子类意外覆盖“私有”属性。

举个例子。有人编写了一个名为 Dog 的类,这个类的内部用到了 mood 实例属性,但是没有将其开放。现在,你创建了 Dog 类的子类:Beagle。如果你在毫不知情的情况下又创建了名为 mood 的实例属性,那么在继承的方法中就会把 Dog 类的 mood 属性覆盖掉。这是个难以调试的问题。

为了避免这种情况,如果以 __mood 的形式(两个前导下划线,尾部没有或最多有一个下划线)命名实例属性,Python 会把属性名存入实例的 __dict__ 属性中,而且会在前面加上一个下划线和类名。因此,对 Dog 类来说,__mood 会变成 _Dog__mood;对 Beagle 类来说,会变成 _Beagle__mood。这个语言特性叫名称改写(name mangling)。

示例 9-10 以示例 9-7 中定义的 Vector2d 类为例来说明名称改写。

示例 9-10 私有属性的名称会被“改写”,在前面加上下划线和类名

>>> v1 = Vector2d(3, 4)
>>> v1.__dict__
{'_Vector2d__y': 4.0, '_Vector2d__x': 3.0}
>>> v1._Vector2d__x
3.0

名称改写是一种安全措施,不能保证万无一失:它的目的是避免意外访问,不能防止故意做错事(图 9-1 也是一种保护装置)。

图 9-1:把手上的盖子是种保护装置,而不是安全装置:它能避免意外触动把手,但是不能防止有意转动

如示例 9-10 中的最后一行所示,只要知道改写私有属性名的机制,任何人都能直接读取私有属性——这对调试和序列化倒是有用。此外,只要编写 v1._Vector__x = 7 这样的代码,就能轻松地为 Vector2d 实例的私有分量直接赋值。如果真在生产环境中这么做了,出问题时可别抱怨。

不是所有 Python 程序员都喜欢名称改写功能,也不是所有人都喜欢 self.__x 这种不对称的名称。有些人不喜欢这种句法,他们约定使用一个下划线前缀编写“受保护”的属性(如 self._x)。批评使用两个下划线这种改写机制的人认为,应该使用命名约定来避免意外覆盖属性。本章开头引用了多产的 Ian Bicking 的一句话,那句话的完整表述如下:

绝对不要使用两个前导下划线,这是很烦人的自私行为。如果担心名称冲突,应该明确使用一种名称改写方式(如 _MyThing_blahblah)。这其实与使用双下划线一样,不过自己定的规则比双下划线易于理解。7

7摘自 Paste 的风格指南

Python 解释器不会对使用单个下划线的属性名做特殊处理,不过这是很多 Python 程序员严格遵守的约定,他们不会在类外部访问这种属性。8 遵守使用一个下划线标记对象的私有属性很容易,就像遵守使用全大写字母编写常量那样容易。

8不过在模块中,顶层名称使用一个前导下划线的话,的确会有影响:对 from mymod import * 来说,mymod 中前缀为下划线的名称不会被导入。然而,依旧可以使用 from mymod import _privatefunc 将其导入。Python 教程的 6.1 节“More on Modules”说明了这一点。

Python 文档的某些角落把使用一个下划线前缀标记的属性称为“受保护的”属性。9 使用 self._x 这种形式保护属性的做法很常见,但是很少有人把这种属性叫作“受保护的”属性。有些人甚至将其称为“私有”属性。

9gettext 模块中就有一个例子

总之,Vector2d 的分量都是“私有的”,而且 Vector2d 实例都是“不可变的”。我用了两对引号,这是因为并不能真正实现私有和不可变。10

10如果这个说法让你感到沮丧,而且让你觉得在这方面 Python 应该向 Java 看齐的话,那么别去读本章的“杂谈”,我在其中对 Java 的 private 修饰符的相对强度进行了探讨。

下面继续定义 Vector2d 类。在最后一节中,我们将讨论一个特殊的属性(不是方法),它会影响对象的内部存储,对内存用量可能也有重大影响,不过对对象的公开接口没什么影响。这个属性是 __slots__。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文