本文目录导读:

我来为你详细介绍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
-
命名约定:
_single_underscore:受保护,表示应该被视为内部使用__double_underscore:私有,触发名称修饰(name mangling)
-
封装目的:
- 保护数据完整性
- 隐藏实现细节
- 提供统一的访问接口
-
使用场景:
- 敏感数据(密码、余额)
- 需要验证的数据(价格、成绩)
- 计算属性(总价、等级)
-
最佳实践:
- 优先使用
@property装饰器 - 提供清晰的getter/setter方法
- 在setter中进行数据验证
- 保持接口简单统一
- 优先使用
这些案例展示了Python中私有属性封装的各种模式,你可以根据实际需求选择合适的方式。