小能豆

为什么 Python 的“私有”方法实际上并不是私有的?

javascript

Python 允许我们在类中创建“私有”方法和变量,只需在名称前面添加双下划线即可,如下所示:__myPrivateMethod()。那么,如何解释这一点呢?

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

这是怎么回事?!

我会向那些不太明白的人稍微解释一下。

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

我创建一个具有公共方法和私有方法的类并实例化它。

接下来,我调用它的公共方法。

>>> obj.myPublicMethod()
public method

接下来,我尝试调用它的私有方法。

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

这里一切看起来都很好;我们无法调用它。事实上,它是“私有的”。嗯,实际上它不是。dir()在对象上运行会显示一种新的神奇方法,Python 会神奇地为所有“私有”方法创建这种方法。

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

这个新方法的名称总是一个下划线,后跟类名,后跟方法名。

>>> obj._MyClass__myPrivateMethod()
this is private!!

封装就这么多,是吧?

无论如何,我一直听说 Python 不支持封装,那为什么还要尝试呢?到底是怎么回事?


阅读 46

收藏
2024-07-02

共1个答案

小能豆

您在 Python 中观察到的有关“私有”方法和名称修改的行为确实是故意的,并且用于特定目的,而不是违反封装。让我们分解一下关键点以更好地理解此行为:

1.“私有”方法的名称修改

在 Python 中,在方法或属性名称前使用双下划线 ( __) 会触发名称改编。名称改编主要是为了避免意外访问和覆盖子类中的属性。当您定义诸如 之类的方法时__myPrivateMethod,Python 会在内部将其重命名为_MyClass__myPrivateMethod。进行这种重命名是为了降低与子类使用的名称意外冲突的可能性。

2. 访问“私有”方法

当您尝试__myPrivateMethod直接访问 的实例时MyClass,Python 找不到名为 的属性,__myPrivateMethod因为它已被破坏。这就是您得到 的原因AttributeError

3. 通过 Mangling 访问名称

尽管通过名称修改实现了表面上的隐私,但 Python 并不强制执行严格的访问控制。相反,它提供了一种使用修改后的名称直接访问这些“私有”方法的方法。当您使用dir(obj)并查看_MyClass__myPrivateMethod列表时会显示这一点。

4. Python 中的封装

Python 的封装方法更多的是约定俗成,而不是严格执行。单下划线 ( _) 前缀通常用于指示“受保护”的属性或方法(供内部使用或供子类使用)。双下划线 ( __) 用于名称修改,以避免意外的名称冲突。

为什么要在 Python 中使用封装?

尽管 Python 不像其他一些语言那样强制执行封装,但它仍然鼓励这样做,原因如下:

  • 清晰度和意图_:使用下划线( )和双下划线( )之类的约定__可以使代码对其他开发人员更清晰,表明哪些部分是供公共使用,哪些部分用于内部实现。
  • 减少意外修改:通过使用名称修改,Python 减少了代码其他部分意外修改或访问类内部的可能性。
  • 继承和子类:名称修改可帮助子类避免与超类中定义的方法发生意外的名称冲突。

结论

Python 的封装方法虽然在访问控制方面并不严格,但提供了名称修改等机制来支持良好的编码实践。虽然可以使用修改后的名称访问“私有”方法,但除非绝对必要,否则通常不建议这样做,因为这会导致代码更难维护且更容易出错。相反,遵守命名约定并对“受保护”的方法和属性使用单下划线通常足以在 Python 中实现封装。

2024-07-02