前言封装把数据和操作数据的方法组织到类中并通过命名约定减少外部对内部状态的误用。本文以 Car 类为例说明公有成员、私有成员和名称改写机制再结合 Python 的“君子协议”解释为什么私有成员可以被访问但不建议直接访问。一、封装解决什么问题一个 Car 对象中品牌、型号、颜色和启动、停止等行为可以直接提供给外部使用车主姓名、油门控制等内容属于对象内部状态或内部动作如果外部随意修改或调用就可能导致对象状态失控。封装主要解决两个问题把数据和操作数据的方法绑定到同一个类中对外提供稳定的使用方式减少外部直接操作内部实现。Python 通过命名规则区分访问意图普通名称表示公有成员名称前加一个下划线表示内部成员名称前加两个下划线表示需要进行名称改写的私有成员。二、公有属性与私有属性下面的 Car 类包含三个公有属性、一个私有属性、三个公有方法和一个私有方法classCar:def__init__(self,brand,model,color,owner):self.brandbrand self.modelmodel self.colorcolor self.__ownerownerdefstart(self):print(f{self.brand}{self.model}正在启动...)defrun(self):print(f{self.__owner}:{self.brand}{self.model}正在行驶...)defstop(self):print(f{self.brand}{self.model}停止行驶...)def__control_fuel(self):print(f{self.brand}{self.model}正在控制油门...)brand、model 和 color 没有特殊前缀是公有属性。owner 写成__owner表示私有属性。start、run 和 stop 是对外提供的公有方法__control_fuel则属于类内部实现。私有限制的是类外部的直接访问并不影响类内部使用。run 方法中可以直接读取self.__owner因为它仍然属于 Car 类的内部代码。三、名称改写私有成员到底存在哪里双下划线成员不会被加密。Python 在创建类时会把类内部以两个下划线开头、结尾不是两个下划线的名称改写为_类名__原名称因此__owner - _Car__owner __control_fuel - _Car__control_fuel可以通过对象的属性字典观察实际保存的名称if__name____main__:carCar(Audi,A6,黑色,张三)print(car.__dict__)print([namefornameindir(car)ifownerinnameorcontrolinname])输出结果中会看到类似内容{brand: Audi, model: A6, color: 黑色, _Car__owner: 张三} [_Car__control_fuel, _Car__owner]__dict__展示对象实例保存的属性dir展示对象能够访问到的成员名称。可以看到车主姓名并没有以__owner的形式保存而是保存成了_Car__owner。如果在类外部直接访问原名称print(car.__owner)car.__control_fuel()程序会抛出AttributeError: Car object has no attribute __owner原因是名称改写只发生在类定义内部。类外部写下car.__owner时解释器不会自动把它改写成_Car__owner。如果直接使用改写后的名称则可以访问print(car._Car__owner)car._Car__control_fuel()这说明 Python 的私有成员只是改了名称并没有形成真正的访问屏障。四、君子协议内部可调用外部遵守约定私有成员主要用于表示类的内部实现。类内部可以正常调用私有方法类外部虽然能通过名称改写后的名字访问它但这不属于推荐用法。classCar:def__init__(self,brand):self.brandbranddefrun(self):self.__control_fuel()def__control_fuel(self):print(f{self.brand}正在控制油门...)carCar(Audi)car.run()# 通过公有方法运行car._Car__control_fuel()# 技术上可以调用但不建议这样做调用 car.run() 时类内部会执行 self.__control_fuel()因此私有方法仍然可以在类内部使用。外部也能通过 _Car__control_fuel 找到这个方法但名称改写后的名称属于实现细节外部代码不应依赖它。这就是 Python 的“君子协议”语言允许访问内部成员但开发者应通过公有方法使用对象并遵守命名所表达的约定。五、总结Python 封装通过类组织数据和行为通过命名规则表达成员的访问意图。双下划线成员会被改写为_类名__原名可以减少外部误用和子类命名冲突但不会提供真正的安全隔离。理解“君子协议”后可以用两个问题判断成员是否适合公开这个成员是否属于稳定的业务接口外部代码是否应该依赖它的具体存储方式如果答案是否定的就应该通过公有方法提供能力而不是直接访问内部属性。
阅读完成 · 觉得有帮助?