当前位置: 首页 > ai >正文

python---封装

文章目录

  • Python 中的封装实现
    • 访问修饰符
  • 私有、保护、公开属性
    • 1. 公开属性
    • 2. 保护属性
    • 3. 私有属性
    • 总结与对比
  • 属性装饰器
    • 只读属性
    • 带验证的 setter
  • 延迟计算属性
    • 使用 property() 函数

封装是面向对象编程的三大核心特性之一(封装、继承、多态)。
封装主要有三个目的:
1、数据隐藏:保护对象的内部状态,防止外部直接访问和修改

2、接口暴露:提供受控的访问方式,通过公共方法操作数据

3、实现隔离:将实现细节隐藏,只暴露必要的功能接口

Python 中的封装实现

访问修饰符

Python 使用命名约定来实现访问控制:

class BankAccount:def __init__(self, account_holder, balance):self.account_holder = account_holder  # 公共属性self._balance = balance  # 受保护的属性(约定)self.__password = "secret"  # 私有属性(名称修饰)# 公共方法def get_balance(self):return self._balance# 受保护的方法def _calculate_interest(self):return self._balance * 0.05# 私有方法def __validate_password(self, input_password):return self.__password == input_password# 通过公共方法访问私有属性def withdraw(self, amount, password):if self.__validate_password(password):if amount <= self._balance:self._balance -= amountreturn Truereturn False

私有、保护、公开属性

Python 中没有真正无法访问的“私有”成员,它主要依靠一种叫做“名称修饰”的约定来实现封装,而不是严格的强制访问控制。
这三种访问级别都是通过命名约定来实现的,旨在向开发者传递明确的意图,而不是限制程序的行为。

1. 公开属性

这是默认的访问级别。任何在类中直接定义的属性(变量或方法)都是公开的。
命名方式:没有任何下划线前缀。例如:name, process_data()。
访问权限:可以从类的外部、子类以及其他任何地方自由访问和修改。
代码示例:

class MyClass:def __init__(self):self.public_attr = "I am public!" # 公开属性self.value = 10def public_method(self): # 公开方法return "Public method called"# 外部自由访问
obj = MyClass()
print(obj.public_attr)   # 输出: I am public!
obj.public_attr = "Changed"
print(obj.public_attr)   # 输出: Changed
print(obj.public_method()) # 输出: Public method called

2. 保护属性

这是一个弱“保护”的指示符。它告诉其他程序员:“这是一个内部属性,除非你知道自己在做什么,否则最好不要在类外部直接访问它。” 但它并不会阻止你访问。
命名方式:以单个下划线开头。例如:_internal_attr, _helper_method()。
访问权限:技术上仍然可以从外部访问,但这是一种约定俗成的信号,意味着“这是内部 API,不稳定,请勿直接使用”。Pylint 等代码检查工具会对此类外部访问发出警告。

from module import * 的影响:使用 from module import * 时,以单下划线开头的变量不会被导入。(不可把其他模块使用)

代码示例:

class MyClass2:def __init__(self):self.public = "public"self._protected_attr = "I am ‘protected‘" # 保护属性def _protected_method(self): # 保护方法return "Protected method called"def use_protected(self):# 在类的内部,可以自由使用保护属性和方法print(self._protected_attr)print(self._protected_method())# 外部仍然可以访问(但不建议这样做)
obj2 = MyClass2()
print(obj2._protected_attr)     # 输出: I am ‘protected‘ (但不推荐)
obj2._protected_attr = "Changed anyway"
print(obj2._protected_attr)     # 输出: Changed anyway (但不推荐)
print(obj2._protected_method())     # 输出: Protected method called (但不推荐)# 推荐的方式是通过公共接口来操作
obj2.use_protected()    # 输出: Changed anyway

3. 私有属性

Python 中最强的“私有”指示符。通过一个叫做“名称修饰”的机制来实现,目的是避免在子类中意外重写私有成员。
命名方式:以双下划线开头(但不以双下划线结尾)。例如:__private_attr, __private_method()。

访问权限:Python 解释器会在运行时自动将私有属性的名称修改为 _类名__属性名 的格式。这使得在类外部通过原始名称直接访问变得困难,但如果你知道修饰后的名称,仍然可以访问。这是一种防止意外访问的机制。

class MyClass:def __init__(self):self.public = "public"self._protected = "protected"self.__private_attr = "I am private" # 私有属性def __private_method(self): # 私有方法return "Private method called"def access_private(self):# 在类的内部,仍然可以使用原始名称访问私有成员print(self.__private_attr)print(self.__private_method())obj = MyClass()# 尝试从外部直接访问私有属性(会失败)
# print(obj.__private_attr)   # AttributeError: 'MyClass' object has no attribute '__private_attr'
# obj.__private_method()      # AttributeError: 'MyClass' object has no attribute '__private_method'# 查看对象的所有属性,可以看到名称已被修饰
print(dir(obj))
# 输出中会包含: ... '_MyClass__private_attr', '_MyClass__private_method' ...# 通过修饰后的名称“强行”访问(虽然能做到,但强烈不建议在生产代码中这样做)
print(obj._MyClass__private_attr)        # 输出: I am private
print(obj._MyClass__private_method())    # 输出: Private method called

名称修饰的核心作用:防止子类意外重写父类的私有属性。

class Parent:def __init__(self):self.__private = "Parent‘s private" # 会被修饰为 _Parent__privatedef get_private(self):return self.__private # 这里访问的是 _Parent__privateclass Child(Parent):def __init__(self):super().__init__()self.__private = "Child‘s private" # 会被修饰为 _Child__private。这是一个全新的属性,与父类的无关。child = Child()
print(child.get_private()) # 输出: "Parent‘s private"
# 因为 Parent 的 get_private 方法寻找的是 _Parent__private,
# 而 Child 实例中的 _Child__private 是完全不同的另一个属性。

总结与对比

类型命名约定访问权限主要目的
公开attribute任意位置均可访问类的公共 API,安全使用。
保护_attribute仍可访问,但会收到警告,在其他模块不可访问提示开发者“这是内部实现,请勿直接使用,因为它可能改变”。
私有__attribute名称被修饰,难以直接访问防止子类意外重写内部属性,实现更强的封装。

属性装饰器

class Person:def __init__(self, name, age):self._name = nameself._age = age# Getter 方法@propertydef name(self):return self._name# Setter 方法@name.setterdef name(self, value):if isinstance(value, str) and len(value) > 0:self._name = valueelse:raise ValueError("姓名必须是非空字符串")@propertydef age(self):return self._age@age.setterdef age(self, value):if 0 <= value <= 120:self._age = valueelse:raise ValueError("年龄必须在0-120之间")# 使用示例
person = Person("张三", 25)
print(person.name)  # 通过属性方式访问
person.age = 30     # 通过属性方式设置,会进行验证

只读属性

class Circle:def __init__(self, radius):self._radius = radius@propertydef radius(self):"""半径(只读)"""return self._radius@propertydef area(self):"""面积(计算属性,只读)"""return 3.14159 * self._radius ** 2circle = Circle(5)
print(f"半径: {circle.radius}")  # 输出: 半径: 5
print(f"面积: {circle.area}")    # 输出: 面积: 78.53975# circle.radius = 10  # 这会报错,因为 radius 是只读的

带验证的 setter

class Temperature:def __init__(self, celsius):self._celsius = celsius@propertydef celsius(self):"""摄氏温度"""return self._celsius@celsius.setterdef celsius(self, value):"""设置摄氏温度,并进行范围验证"""if value < -273.15:raise ValueError("温度不能低于绝对零度(-273.15°C)")self._celsius = value@propertydef fahrenheit(self):"""华氏温度(计算属性)"""return self._celsius * 9/5 + 32@fahrenheit.setterdef fahrenheit(self, value):"""通过华氏温度设置摄氏温度"""self.celsius = (value - 32) * 5/9temp = Temperature(25)
print(f"摄氏: {temp.celsius}°C")        # 输出: 摄氏: 25°C
print(f"华氏: {temp.fahrenheit}°F")     # 输出: 华氏: 77.0°Ftemp.fahrenheit = 100
print(f"摄氏: {temp.celsius}°C")        # 输出: 摄氏: 37.77777777777778°C

延迟计算属性

class ExpensiveComputation:def __init__(self, data):self._data = dataself._result = Noneself._is_computed = False@propertydef result(self):"""延迟计算的昂贵操作结果"""if not self._is_computed:print("正在进行昂贵计算...")self._result = self._expensive_computation()self._is_computed = Truereturn self._resultdef _expensive_computation(self):# 模拟昂贵计算return sum(x * 2 for x in self._data)data = [1, 2, 3, 4, 5]
comp = ExpensiveComputation(data)print("第一次访问:")
print(comp.result)  # 会进行计算print("第二次访问:")
print(comp.result)  # 直接返回缓存结果

使用 property() 函数

除了装饰器语法,可以使用 property() 函数:

class Rectangle:def __init__(self, width, height):self._width = widthself._height = heightdef get_area(self):return self._width * self._heightdef set_width(self, value):if value <= 0:raise ValueError("宽度必须大于0")self._width = valuedef get_width(self):return self._width# 使用 property() 函数width = property(get_width, set_width)area = property(get_area)rect = Rectangle(10, 5)
print(f"宽度: {rect.width}")    # 输出: 宽度: 10
print(f"面积: {rect.area}")     # 输出: 面积: 50rect.width = 15
print(f"新面积: {rect.area}")   # 输出: 新面积: 75
http://www.xdnf.cn/news/19372.html

相关文章:

  • MySQL 8 的 SQL 语法新特性
  • 《哲思:生命与宇宙的终极意义》
  • 【Canvas技法】绘制横向多色旗和竖向多色旗
  • Python入门教程:常用第三方库Matplotlib(基本用法)下载、安装、参数解析教程
  • ibping基本使用 以及 包丢失 超时 排障
  • 设计模式 | 常见的设计模式(单例、工厂、代理、适配器、责任链等等)
  • 2025年9月计算机二级C++语言程序设计——选择题打卡Day12
  • Langflow 多模态技术深度分析
  • Hysplit大气传输和污染扩散-轨迹聚合标准20%30%用途
  • OpenCV 图像直方图与对比度增强实战:从分析到优化
  • Week 14: 深度学习补遗:迁移学习
  • 《隐性质量:决定软件生命周期的看不见的竞争力》
  • Langflow Agents 技术深度分析
  • 极客学院-从零开始学架构
  • MCP SDK 示例一
  • Linux 特殊文件系统
  • 二、程序设计语言基础知识
  • 预售破 500 万!淮北吾悦广场京东奥莱8月29日开业燃动皖北
  • Pytest+Selenium4 Web自动化测试框架(三日速通)
  • ANR InputDispatching TimeOut超时判断 - android-15.0.0_r23
  • python如何打开显示svg图片
  • react-beautiful-dnd ​React 拖拽(Drag and Drop)库
  • Scikit-learn Python机器学习 - 类别特征提取- OneHotEncoder
  • 人工智能-python-深度学习-
  • RPC个人笔记(包含动态代理)
  • HarmonyOS 应用开发:基于API 12+的现代化开发实践
  • shell编程基础入门-2
  • 层次分析法
  • 现代C++特性 并发编程:线程管理库 <thread>(C++11)
  • dayjs 常用方法总结