Python私有属性案例如何封装数据

wen python案例 26

本文目录导读:

Python私有属性案例如何封装数据

  1. 基础私有属性封装
  2. 使用@property装饰器
  3. 完整封装案例:用户管理系统
  4. 更高级的封装:数据校验和转换
  5. 封装的最佳实践

我来为你详细介绍Python私有属性的封装案例,包含多种使用场景。

基础私有属性封装

class BankAccount:
    def __init__(self, account_holder, initial_balance=0):
        self._account_holder = account_holder  # 受保护属性(约定)
        self.__balance = initial_balance  # 私有属性(名称修饰)
    # getter方法
    def get_balance(self):
        return self.__balance
    # setter方法
    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("存款金额必须大于0")
        self.__balance += amount
    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("取款金额必须大于0")
        if amount > self.__balance:
            raise ValueError("余额不足")
        self.__balance -= amount
# 测试
account = BankAccount("张三", 1000)
print(account.get_balance())  # 1000
account.deposit(500)
account.withdraw(200)
print(account.get_balance())  # 1300
# 无法直接访问私有属性
# print(account.__balance)  # AttributeError
# 名称修饰后的访问(不推荐)
print(account._BankAccount__balance)  # 1300

使用@property装饰器

class Student:
    def __init__(self, name, score):
        self.__name = name
        self.__score = score
    @property
    def name(self):
        """姓名属性,只读"""
        return self.__name
    @property
    def score(self):
        """成绩属性,可读写"""
        return self.__score
    @score.setter
    def score(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError("成绩必须是数字")
        if value < 0 or value > 100:
            raise ValueError("成绩必须在0-100之间")
        self.__score = value
    @property
    def grade(self):
        """计算等级,只读属性"""
        if self.__score >= 90:
            return 'A'
        elif self.__score >= 80:
            return 'B'
        elif self.__score >= 70:
            return 'C'
        elif self.__score >= 60:
            return 'D'
        else:
            return 'F'
# 测试
student = Student("小明", 85)
print(student.name)  # 小明
print(student.score)  # 85
student.score = 92  # 使用setter
print(student.score)  # 92
print(student.grade)  # A
# student.name = "小红"  # AttributeError, name是只读的

完整封装案例:用户管理系统

from datetime import datetime
import re
class User:
    def __init__(self, username, email, password):
        self.__id = None
        self.__username = username
        self.__email = email
        self.__password = self.__encrypt_password(password)
        self.__created_at = datetime.now()
        self.__last_login = None
        self.__is_active = True
    # 私有方法
    def __encrypt_password(self, password):
        """加密密码(简化示例)"""
        return hash(password)
    def __validate_email(self, email):
        """验证邮箱格式"""
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return re.match(pattern, email) is not None
    # 属性getter
    @property
    def id(self):
        return self.__id
    @property
    def username(self):
        return self.__username
    @property
    def email(self):
        return self.__email
    @email.setter
    def email(self, new_email):
        if not self.__validate_email(new_email):
            raise ValueError("邮箱格式不正确")
        self.__email = new_email
    @property
    def created_at(self):
        return self.__created_at
    @property
    def last_login(self):
        return self.__last_login
    @property
    def is_active(self):
        return self.__is_active
    # 公共方法
    def login(self, password):
        if not self.__is_active:
            raise Exception("账户已被禁用")
        if hash(password) != self.__password:
            return False
        self.__last_login = datetime.now()
        return True
    def change_password(self, old_password, new_password):
        if hash(old_password) != self.__password:
            raise ValueError("原密码不正确")
        if len(new_password) < 8:
            raise ValueError("新密码长度至少8位")
        self.__password = self.__encrypt_password(new_password)
    def deactivate(self):
        """停用账户"""
        self.__is_active = False
    def activate(self):
        """激活账户"""
        self.__is_active = True
    def to_dict(self):
        """转换为字典(不包含敏感信息)"""
        return {
            'id': self.__id,
            'username': self.__username,
            'email': self.__email,
            'created_at': self.__created_at.isoformat(),
            'last_login': self.__last_login.isoformat() if self.__last_login else None,
            'is_active': self.__is_active
        }
# 使用示例
user = User("john_doe", "john@example.com", "password123")
print(user.username)  # john_doe
print(user.email)     # john@example.com
# 修改邮箱
user.email = "new_email@example.com"
# 登录
if user.login("password123"):
    print("登录成功")
    print(f"最后登录时间: {user.last_login}")
# 修改密码
user.change_password("password123", "new_password_123")
# 输出用户信息(不含密码)
print(user.to_dict())

更高级的封装:数据校验和转换

class Temperature:
    def __init__(self, celsius=0):
        self.__celsius = celsius
    @property
    def celsius(self):
        return self.__celsius
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self.__celsius = value
    @property
    def fahrenheit(self):
        """计算华氏温度(只读)"""
        return (self.__celsius * 9/5) + 32
    @fahrenheit.setter
    def fahrenheit(self, value):
        """设置华氏温度"""
        if value < -459.67:
            raise ValueError("温度不能低于绝对零度")
        self.__celsius = (value - 32) * 5/9
    @property
    def kelvin(self):
        """计算开尔文温度(只读)"""
        return self.__celsius + 273.15
    def __str__(self):
        return f"{self.__celsius:.2f}°C ({self.fahrenheit:.2f}°F, {self.kelvin:.2f}K)"
# 测试
temp = Temperature(25)
print(temp)  # 25.00°C (77.00°F, 298.15K)
temp.celsius = 100
print(temp.fahrenheit)  # 212.0
temp.fahrenheit = 32
print(temp.celsius)  # 0.0
print(temp.kelvin)   # 273.15

封装的最佳实践

class Product:
    def __init__(self, name, price, quantity):
        # 使用单下划线表示受保护(子类可访问)
        self._name = name
        # 使用双下划线表示私有(子类不可直接访问)
        self.__price = price
        self.__quantity = quantity
        self.__version = 1
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, value):
        if not value or not isinstance(value, str):
            raise ValueError("产品名称不能为空")
        self._name = value
    @property
    def price(self):
        return self.__price
    @price.setter
    def price(self, value):
        if value <= 0:
            raise ValueError("价格必须大于0")
        self.__price = value
        self.__version += 1  # 更新版本号
    @property
    def quantity(self):
        return self.__quantity
    @quantity.setter
    def quantity(self, value):
        if value < 0:
            raise ValueError("数量不能为负")
        self.__quantity = value
        self.__version += 1
    @property
    def total_value(self):
        """总价值(只读)"""
        return self.__price * self.__quantity
    @property
    def version(self):
        """版本号(只读)"""
        return self.__version
# 测试
product = Product("笔记本电脑", 5999.99, 10)
print(f"产品: {product.name}")
print(f"价格: {product.price}")
print(f"总价值: {product.total_value}")
product.price = 5499.99
product.quantity = 15
print(f"更新后总价值: {product.total_value}")
print(f"版本号: {product.version}")  # 3
  1. 命名约定

    • _single_underscore:受保护,表示应该被视为内部使用
    • __double_underscore:私有,触发名称修饰(name mangling)
  2. 封装目的

    • 保护数据完整性
    • 隐藏实现细节
    • 提供统一的访问接口
  3. 使用场景

    • 敏感数据(密码、余额)
    • 需要验证的数据(价格、成绩)
    • 计算属性(总价、等级)
  4. 最佳实践

    • 优先使用@property装饰器
    • 提供清晰的getter/setter方法
    • 在setter中进行数据验证
    • 保持接口简单统一

这些案例展示了Python中私有属性封装的各种模式,你可以根据实际需求选择合适的方式。

抱歉,评论功能暂时关闭!