Skip to content

Python 缺少真正的 OOP 封装

True OOP Encapsulation is Missing From Python

使用访问修饰符(public、protected 和 private)是 OOP 中封装(encapsulation)的基础。

ds p513 1

这不仅是 Python 的问题,也适用于一般的 OOP。然而,当我们具体谈论 Python 时,会发现它没能提供真正的封装机制,而封装正是人们在 OOP 代码中想要利用的特性。怎么回事呢?我们就在本章中搞清楚。你可能已经知道,OOP 中类的属性可以分为三类:

  • 公有成员(public)在基类内外都可以被访问,并且会被所有子类继承。
  • 受保护成员(protected)在基类和子类中都可以被访问,但在类外部不可访问。
  • 私有成员(private)只能在基类内部被访问。

但是,在 Python 中并没有这样严格的强制。这与 C++ 等许多其他编程语言不同。因此,受保护成员的行为与公有成员完全一样。更有甚者,私有成员也可以(以某种方式)在类外部被访问到。

为了更清楚地说明,来看下面这个类的实现:

ds p514 1

从语法上讲,在 Python 中:

  • 公有成员用 0 个前导下划线声明。
  • 受保护成员用 1 个前导下划线声明。
  • 私有成员用 2 个前导下划线声明。

接下来,我们实例化一个类对象:

ds p514 2

继续,正如人们所预期的,公有属性可以在类外部被访问:

ds p514 3

然而,受保护属性同样也能在类外部被访问,而理想情况下这本不应该发生:

ds p515 1

最后,在声明私有成员时,Python 会执行名称改写(name mangling)。这是一种编程中用来避免不同类之间命名冲突的技术。Python 通过给所有带两个前导下划线的成员附加下划线前缀的类名(_Class)来进行名称改写。

ds p515 2

因此,尽管私有成员无法用其原始名字直接访问,但仍然可以用名称改写后得到的那个名字来访问它。

这一点在下面得到了演示:

ds p516 1

正如上述所有示例所展示的那样,受保护成员和私有成员(借助名称改写)都能像公有成员一样被访问。因此,每一位使用 OOP 的 Python 程序员都必须记住:Python 从来不会强制执行封装。相反,在 Python 中利用封装机制主要依靠约定。这些约定用来向其他程序员传达类成员的可访问性规则。

ds p516 2

因此,遵守这些约定是程序员自己的责任。

本站内容仅供学习交流,版权归原作者所有。