问题的历史 在经典的面向对象编程中,封装是通过限制对内部数据的访问来实现的。在大多数语言中,有严格的访问修饰符。在Python中,遵循原则“我们都是成年人”——没有严格的私密性。
问题 开发人员常常混淆Python中的受保护(_protected)和私有(__private)属性和方法,认为“双下划线”提供了完备的保护,或者认为根本没有保护。
解决方案
Python实现了约定:单下划线 _var 表示受保护,双下划线 __var 表示私有(名称重整)。对这样的属性或方法的访问是可能的,但更困难:调用方式是 _ClassName__var。
代码示例:
class Example: def __init__(self): self._protected = 1 # 受保护 self.__private = 2 # 私有(名称重整) ex = Example() print(ex._protected) # 1 #print(ex.__private) # AttributeError print(ex._Example__private) # 2 (名称重整)
关键特性:
可以通过实例访问带双下划线的“私有”字段吗?
可以,通过名称重整:_ClassName__var。所以数据是可访问的,只是不明确而已。
在继承时,私有方法/属性的行为如何?
名称重整防止了子类意外重写父类的私有元素,但可以通过 _ParentClass__attr 访问。带双下划线的方法在子类外部是“不可见”的。
class A: def __foo(self): print("A") class B(A): def bar(self): # self.__foo() — 错误 self._A__foo() # 可行
Python有完全的私密性吗,如同JVM/C++?
没有。所有内容都基于约定和名称重整。无法完全保护数据,因为Python动态允许访问任何属性。
在一个大型库中,用户试图通过双下划线更改私有属性,认为这是“秘密”——但通过 _ClassName__var 修改仍然发生。
优点:
缺点:
在项目中约定使用单下划线表示内部字段,并且不在类外进行修改。添加属性以实现安全访问。
优点:
缺点: