面向对象编程有三大核心特性: 封装、继承和多态。这些特性使得代码更加模块化、可重用和易于维护。
引入
问题导出: 在实际的问卷调查系统中,当用户填写个人信息时,性别字段通常应该限定为“男”或“女”两种选项。如果系统不对输入进行验证,用户可能会随意填写如“保密”、“未知”等不符合规范的值,导致后续数据分析时出现数据混乱,无法准确统计男女比例,影响调查结果的准确性。
无封装:
class Person:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex # 直接暴露,无法验证输入
self.age = age
def __str__(self):
return f"我叫{self.name},性别是{self.sex},年龄是{self.age}"
p = Person("张三", "帅哥", 18) # 性别被设置为不合理的"帅哥"
print(p) # 输出异常结果
解决方案:
使用封装!!!
将gender设为私有属性,即"__gender"
通过公共方法控制对属性的访问和修改
在setter方法中添加数据验证,确保性别只能是"男"或"女"
有封装:
class Person:
def __init__(self, name, age):
self.name = name
self.__sex = "未知" # 默认值
self.age = age
# 给属性设置一个可以对外调用的方法
def get_sex(self):
return self.__sex
# 给属性设置一个可以对外访问的方法
def set_sex(self, sex):
if sex == "男" or sex == "女":
self.__sex = sex
else:
print("性别错误")
def __str__(self):
return f"我是{self.name},我的性别是{self.get_sex()},{self.age}岁"
p = Person("张三", 18)
p.set_sex("帅哥")
print(p)
输出:

这就是封装的意义。
1. 封装的概念
封装是将数据(属性)和行为(方法)包装在一起,并隐藏内部实现细节的过程。
通过封装,我们可以控制对对象内部状态的访问。
2. 访问控制
在⾯向对象代码中,我们可以把属性和⽅法分为两⼤类:公有(属性、⽅法)、私有(属性、⽅法)
公有属性和公有⽅法:⽆论在类的内部还是在类的外部我们都可以对属性和⽅法进⾏操作。
但是有些情况下,我们不希望在类的外部对类内部的属性和⽅法进⾏操作。我们就可以把这个属性或⽅法封装成私有形式。
Python使用命名约定来实现访问控制,并定义函数名get_xx ⽤来获取私有属性,定义set_xx⽤来修改私有属性值。
示例:
class BankAccount:
def __init__(self, account_holder, initial_balance=0):
# 公有属性 - 可以在外部直接访问
self.account_holder = account_holder
# 保护属性 - 单个下划线开头,暗示"不要直接访问"
self._account_number = self._generate_account_number()
# 私有属性 - 双下划线开头,Python会进行名称修饰
self.__balance = initial_balance
def _generate_account_number(self):
# 保护方法
import random
return f"ACC{random.randint(100000, 999999)}"
def __validate_amount(self, amount):
# 私有方法
return amount > 0
# 公有方法 - 提供对私有属性的受控访问
def deposit(self, amount):
if self.__validate_amount(amount):
self.__balance += amount
return f"存款成功,余额: {self.__balance}"
return "存款金额无效"
def withdraw(self, amount):
if self.__validate_amount(amount) and amount <= self.__balance:
self.__balance -= amount
return f"取款成功,余额: {self.__balance}"
return "取款金额无效或余额不足"
def get_balance(self):
# 提供只读访问
return self.__balance
# 使用封装
account = BankAccount("张三", 1000)
# 可以访问公有属性
print(account.account_holder) # 张三
# 可以访问保护属性(但不推荐)
print(account._account_number) # ACC123456
# 不能直接访问私有属性
# print(account.__balance) # 报错:AttributeError
# 通过公有方法访问
print(account.deposit(500)) # 存款成功,余额: 1500
print(account.withdraw(200)) # 取款成功,余额: 1300
print(account.get_balance()) # 1300
输出:

3. 属性装饰器 — 更好的封装方式
属性装饰器 (@property) 是Python中用于将方法转换为属性的强大工具,它允许我们以访问属性的方式调用方法,同时可以在方法内部添加额外的逻辑。
- @property: 将方法转换为只读属性
- @属性名.setter: 为属性创建设置器方法
- @属性名.deleter: 为属性创建删除器方法
示例:
class Person:
def __init__(self, name, age):
# 使用下划线表示"受保护"的属性
self._name = name
self._age = age
@property
def name(self):
"""获取姓名(只读)"""
return self._name
@property
def age(self):
"""获取年龄"""
return self._age
@age.setter
def age(self, value):
"""设置年龄,带有验证"""
if 0 <= value <= 150:
self._age = value
else:
raise ValueError("年龄必须在0-150之间")
@age.deleter
def age(self):
"""删除年龄时的操作"""
print("年龄属性被删除")
self._age = 0
# 使用属性装饰器
person = Person("李四", 25)
print(person.name) # 李四 - 像属性一样访问,实际上是调用方法
print(person.age) # 25
person.age = 30 # 调用setter方法
print(person.age) # 30
# person.name = "王五" # 报错!name是只读的
try:
person.age = 200 # 触发验证
except ValueError as e:
print(f"错误: {e}") # 错误: 年龄必须在0-150之间
del person.age # 调用deleter方法
print(person.age) # 0
详细说明:
- 只读属性 - name
@property
def name(self):
return self._name
- 只有getter方法,没有setter
- 外部只能读取,不能修改
- person.name = “新值” 会报错
- 可读写属性 - age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if 0 <= value <= 150:
self._age = value
else:
raise ValueError("年龄必须在0-150之间")
- 包含getter和setter
- setter中添加了验证逻辑
- 确保年龄值在合理范围内
- 删除器 - age
@age.deleter
def age(self):
print("年龄属性被删除")
self._age = 0
- 定义删除属性时的行为
- 不是真正删除属性,而是执行特定操作
- 注意事项:
属性名不能与实例变量名相同,否则会造成递归调用
使用下划线前缀表示"内部使用"的变量
只定义getter不定义setter可以创建只读属性
4. 封装的好处
- 安全性:防止数据被意外修改
- 易用性:用户只需要知道简单的接口
- 维护性:内部实现可以改变而不影响外部代码
- 可测试性:可以单独测试每个模块
继承:
https://blog.youkuaiyun.com/2301_80809484/article/details/155110603?spm=1001.2014.3001.5501
1211

被折叠的 条评论
为什么被折叠?



