python @修饰符_fluent python 9.7节 Python的私有属性和“受保护的”属性

5754ba0ea31f0fd78a51149cecc98108.png

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

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

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

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

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

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

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

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

Python 解释器不会对使用单个下划线的属性名做特殊处理,不过这是很多 Python 程序员严格遵守的约定,他们不会在类外部访问这种属性。

遵守使用一个下划线标记对象的私有属性很容易,就像遵守使用全大写 字母编写常量那样容易。

不过在模块中,顶层名称使用一个前导下划线的话,的确会有影响:对 from mymod import * 来说,mymod 中前缀为下划线的名称不会被导入。然而,依旧可以使用 from mymod import _privatefunc 将其导入。Python 教程的 6.1 节“More on Modules”(https://docs.python.org/3/tutorial/modules.html#more-on-modules)说明了这一点。

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值