Python封装完全指南:属性保护与访问控制


面向对象编程有三大核心特性: 封装、继承和多态。这些特性使得代码更加模块化、可重用和易于维护。

引入

问题导出: 在实际的问卷调查系统中,当用户填写个人信息时,性别字段通常应该限定为“男”或“女”两种选项。如果系统不对输入进行验证,用户可能会随意填写如“保密”、“未知”等不符合规范的值,导致后续数据分析时出现数据混乱,无法准确统计男女比例,影响调查结果的准确性。

无封装:

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

详细说明:

  1. 只读属性 - name
@property
def name(self):
    return self._name
  • 只有getter方法,没有setter
  • 外部只能读取,不能修改
  • person.name = “新值” 会报错
  1. 可读写属性 - 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中添加了验证逻辑
  • 确保年龄值在合理范围内
  1. 删除器 - age
@age.deleter
def age(self):
    print("年龄属性被删除")
    self._age = 0
  • 定义删除属性时的行为
  • 不是真正删除属性,而是执行特定操作
  1. 注意事项:

属性名不能与实例变量名相同,否则会造成递归调用
使用下划线前缀表示"内部使用"的变量
只定义getter不定义setter可以创建只读属性


4. 封装的好处

  1. 安全性:防止数据被意外修改
  2. 易用性:用户只需要知道简单的接口
  3. 维护性:内部实现可以改变而不影响外部代码
  4. 可测试性:可以单独测试每个模块

继承:
https://blog.youkuaiyun.com/2301_80809484/article/details/155110603?spm=1001.2014.3001.5501

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值