Python教程(二十四):封装和抽象
off999 2025-08-01 20:05 105 浏览 0 评论
昨天,我们学习了继承和多态,掌握了面向对象编程的核心概念。今天,我们将学习封装和抽象 — 面向对象编程的另外两个重要支柱。
封装保护数据并提供受控的访问,而抽象则隐藏复杂性并提供简洁的接口。
今天您将学习什么
- 什么是封装以及如何实现封装
- 访问修饰符和属性装饰器
- 抽象类和抽象方法
- 接口和抽象基类
- 真实世界示例:银行账户、数据库连接、日志系统
什么是封装?
封装是面向对象编程的核心概念之一,它将数据(属性)和操作数据的方法(行为)捆绑在一起,并隐藏内部实现细节。
封装的优势:
- 数据保护:防止外部直接访问和修改数据
- 接口简化:提供清晰的公共接口
- 维护性:内部实现可以改变而不影响外部代码
- 数据验证:在数据访问时进行验证
1. 基本封装
使用私有属性
class BankAccount:
"""银行账户类 - 封装示例"""
def __init__(self, account_number, owner_name, initial_balance=0):
# 私有属性(以双下划线开头)
self.__account_number = account_number
self.__owner_name = owner_name
self.__balance = initial_balance
self.__transactions = []
self.__is_active = True
# 公共方法 - 提供受控的访问
def get_balance(self):
"""获取余额"""
return self.__balance
def get_account_info(self):
"""获取账户信息"""
return {
'account_number': self.__account_number,
'owner_name': self.__owner_name,
'balance': self.__balance,
'is_active': self.__is_active
}
def deposit(self, amount):
"""存款"""
if not self.__is_active:
print("账户已被冻结,无法存款")
return False
if amount <= 0:
print("存款金额必须大于0")
return False
self.__balance += amount
self.__add_transaction('deposit', amount)
print(f"存款成功:{amount}元,当前余额:{self.__balance}元")
return True
def withdraw(self, amount):
"""取款"""
if not self.__is_active:
print("账户已被冻结,无法取款")
return False
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self.__balance:
print("余额不足")
return False
self.__balance -= amount
self.__add_transaction('withdraw', amount)
print(f"取款成功:{amount}元,当前余额:{self.__balance}元")
return True
# 私有方法 - 内部使用
def __add_transaction(self, transaction_type, amount):
"""添加交易记录"""
transaction = {
'type': transaction_type,
'amount': amount,
'balance': self.__balance,
'timestamp': '2025-07-15 10:30:00' # 简化时间戳
}
self.__transactions.append(transaction)
def get_transaction_history(self):
"""获取交易历史(只读)"""
return self.__transactions.copy() # 返回副本,防止外部修改
def freeze_account(self):
"""冻结账户"""
self.__is_active = False
print(f"账户{self.__account_number}已被冻结")
def unfreeze_account(self):
"""解冻账户"""
self.__is_active = True
print(f"账户{self.__account_number}已解冻")
# 使用封装的银行账户
account = BankAccount("001", "张三", 1000)
# 正确的访问方式
print(f"余额:{account.get_balance()}元")
print(f"账户信息:{account.get_account_info()}")
# 进行交易
account.deposit(500)
account.withdraw(200)
# 查看交易历史
transactions = account.get_transaction_history()
print(f"交易历史:{transactions}")
# 尝试直接访问私有属性(会失败)
try:
print(account.__balance) # AttributeError
except AttributeError:
print("无法直接访问私有属性")2. 属性装饰器
使用@property
class Temperature:
"""温度类 - 属性装饰器示例"""
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
"""摄氏度属性(只读)"""
return self._celsius
@celsius.setter
def celsius(self, value):
"""设置摄氏度(带验证)"""
if value < -273.15:
raise ValueError("温度不能低于绝对零度(-273.15°C)")
self._celsius = value
@property
def fahrenheit(self):
"""华氏度属性(计算属性)"""
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
"""设置华氏度"""
self.celsius = (value - 32) * 5/9
@property
def kelvin(self):
"""开尔文温度属性(计算属性)"""
return self._celsius + 273.15
@kelvin.setter
def kelvin(self, value):
"""设置开尔文温度"""
if value < 0:
raise ValueError("开尔文温度不能为负")
self.celsius = value - 273.15
# 使用属性装饰器
temp = Temperature(25)
print(f"摄氏度:{temp.celsius}°C")
print(f"华氏度:{temp.fahrenheit}°F")
print(f"开尔文:{temp.kelvin}K")
# 设置温度
temp.celsius = 30
print(f"新的摄氏度:{temp.celsius}°C")
temp.fahrenheit = 86
print(f"新的华氏度:{temp.fahrenheit}°F")
# 验证温度
try:
temp.celsius = -300 # 会抛出异常
except ValueError as e:
print(f"错误:{e}")真实世界示例1:数据库连接管理器
import sqlite3
import threading
from contextlib import contextmanager
class DatabaseConnection:
"""数据库连接类 - 封装示例"""
def __init__(self, database_path):
self._database_path = database_path
self._connection = None
self._lock = threading.Lock()
self._is_connected = False
def connect(self):
"""连接数据库"""
if self._is_connected:
print("数据库已连接")
return
try:
self._connection = sqlite3.connect(self._database_path)
self._is_connected = True
print(f"成功连接到数据库:{self._database_path}")
except Exception as e:
print(f"连接数据库失败:{e}")
raise
def disconnect(self):
"""断开数据库连接"""
if not self._is_connected:
print("数据库未连接")
return
try:
self._connection.close()
self._is_connected = False
self._connection = None
print("数据库连接已断开")
except Exception as e:
print(f"断开数据库连接失败:{e}")
def execute_query(self, query, parameters=None):
"""执行查询"""
if not self._is_connected:
raise RuntimeError("数据库未连接")
with self._lock: # 线程安全
try:
cursor = self._connection.cursor()
if parameters:
cursor.execute(query, parameters)
else:
cursor.execute(query)
if query.strip().upper().startswith('SELECT'):
return cursor.fetchall()
else:
self._connection.commit()
return cursor.rowcount
except Exception as e:
self._connection.rollback()
raise RuntimeError(f"查询执行失败:{e}")
@contextmanager
def transaction(self):
"""事务管理器"""
if not self._is_connected:
raise RuntimeError("数据库未连接")
try:
yield self
self._connection.commit()
except Exception:
self._connection.rollback()
raise
def get_connection_status(self):
"""获取连接状态"""
return {
'is_connected': self._is_connected,
'database_path': self._database_path
}
def __enter__(self):
"""上下文管理器入口"""
self.connect()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""上下文管理器出口"""
self.disconnect()
# 使用数据库连接管理器
def create_sample_database():
"""创建示例数据库"""
db = DatabaseConnection(":memory:") # 内存数据库
with db:
# 创建表
db.execute_query("""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
age INTEGER
)
""")
# 插入数据
db.execute_query(
"INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
("张三", "zhangsan@email.com", 25)
)
db.execute_query(
"INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
("李四", "lisi@email.com", 30)
)
# 查询数据
results = db.execute_query("SELECT * FROM users")
print("用户数据:")
for row in results:
print(f" ID: {row[0]}, 姓名: {row[1]}, 邮箱: {row[2]}, 年龄: {row[3]}")
return db
# 使用事务
def demonstrate_transaction():
"""演示事务使用"""
db = DatabaseConnection(":memory:")
with db:
# 创建表
db.execute_query("""
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
name TEXT,
balance REAL
)
""")
# 使用事务
with db.transaction():
db.execute_query(
"INSERT INTO accounts (name, balance) VALUES (?, ?)",
("账户A", 1000)
)
db.execute_query(
"INSERT INTO accounts (name, balance) VALUES (?, ?)",
("账户B", 500)
)
# 转账操作
db.execute_query(
"UPDATE accounts SET balance = balance - 200 WHERE name = ?",
("账户A",)
)
db.execute_query(
"UPDATE accounts SET balance = balance + 200 WHERE name = ?",
("账户B",)
)
# 查看结果
results = db.execute_query("SELECT * FROM accounts")
print("转账后的账户余额:")
for row in results:
print(f" {row[1]}: {row[2]}元")
# 运行示例
print("=== 数据库连接示例 ===")
create_sample_database()
print("\n=== 事务示例 ===")
demonstrate_transaction()真实世界示例2:日志系统
import logging
import os
from datetime import datetime
from enum import Enum
class LogLevel(Enum):
"""日志级别枚举"""
DEBUG = logging.DEBUG
INFO = logging.INFO
WARNING = logging.WARNING
ERROR = logging.ERROR
CRITICAL = logging.CRITICAL
class Logger:
"""日志系统类 - 封装示例"""
def __init__(self, name, log_file=None, level=LogLevel.INFO):
self._name = name
self._log_file = log_file
self._level = level
self._logger = None
self._formatter = None
self._handlers = []
self._setup_logger()
def _setup_logger(self):
"""设置日志器"""
self._logger = logging.getLogger(self._name)
self._logger.setLevel(self._level.value)
# 创建格式化器
self._formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# 添加控制台处理器
console_handler = logging.StreamHandler()
console_handler.setFormatter(self._formatter)
self._logger.addHandler(console_handler)
self._handlers.append(console_handler)
# 添加文件处理器(如果指定了日志文件)
if self._log_file:
file_handler = logging.FileHandler(self._log_file, encoding='utf-8')
file_handler.setFormatter(self._formatter)
self._logger.addHandler(file_handler)
self._handlers.append(file_handler)
def debug(self, message):
"""记录调试信息"""
self._logger.debug(message)
def info(self, message):
"""记录一般信息"""
self._logger.info(message)
def warning(self, message):
"""记录警告信息"""
self._logger.warning(message)
def error(self, message):
"""记录错误信息"""
self._logger.error(message)
def critical(self, message):
"""记录严重错误信息"""
self._logger.critical(message)
def log_with_context(self, level, message, context=None):
"""记录带上下文的日志"""
if context:
message = f"{message} | 上下文: {context}"
if level == LogLevel.DEBUG:
self.debug(message)
elif level == LogLevel.INFO:
self.info(message)
elif level == LogLevel.WARNING:
self.warning(message)
elif level == LogLevel.ERROR:
self.error(message)
elif level == LogLevel.CRITICAL:
self.critical(message)
def get_log_file_path(self):
"""获取日志文件路径"""
return self._log_file
def get_logger_info(self):
"""获取日志器信息"""
return {
'name': self._name,
'level': self._level.name,
'log_file': self._log_file,
'handlers_count': len(self._handlers)
}
class ApplicationLogger:
"""应用程序日志管理器 - 抽象示例"""
def __init__(self, app_name):
self._app_name = app_name
self._loggers = {}
self._setup_loggers()
def _setup_loggers(self):
"""设置各种日志器"""
# 创建日志目录
log_dir = f"logs/{self._app_name}"
os.makedirs(log_dir, exist_ok=True)
# 系统日志
self._loggers['system'] = Logger(
f"{self._app_name}.system",
f"{log_dir}/system.log",
LogLevel.INFO
)
# 错误日志
self._loggers['error'] = Logger(
f"{self._app_name}.error",
f"{log_dir}/error.log",
LogLevel.ERROR
)
# 访问日志
self._loggers['access'] = Logger(
f"{self._app_name}.access",
f"{log_dir}/access.log",
LogLevel.INFO
)
def log_system_event(self, message, level=LogLevel.INFO):
"""记录系统事件"""
self._loggers['system'].log_with_context(level, message)
def log_error(self, error_message, error_details=None):
"""记录错误"""
context = f"错误详情: {error_details}" if error_details else None
self._loggers['error'].error(f"错误: {error_message}")
if context:
self._loggers['error'].error(context)
def log_access(self, user_id, action, resource):
"""记录访问日志"""
message = f"用户 {user_id} 执行了 {action} 操作,资源: {resource}"
self._loggers['access'].info(message)
def get_logger(self, logger_type):
"""获取特定类型的日志器"""
return self._loggers.get(logger_type)
def get_all_loggers_info(self):
"""获取所有日志器信息"""
return {
logger_type: logger.get_logger_info()
for logger_type, logger in self._loggers.items()
}
# 使用日志系统
def demonstrate_logging():
"""演示日志系统使用"""
# 创建应用程序日志管理器
app_logger = ApplicationLogger("MyApp")
# 记录系统事件
app_logger.log_system_event("应用程序启动", LogLevel.INFO)
app_logger.log_system_event("数据库连接成功", LogLevel.INFO)
app_logger.log_system_event("内存使用率较高", LogLevel.WARNING)
# 记录错误
try:
# 模拟错误
result = 10 / 0
except Exception as e:
app_logger.log_error("除零错误", str(e))
# 记录访问日志
app_logger.log_access("user123", "登录", "系统")
app_logger.log_access("user123", "查看", "用户资料")
app_logger.log_access("user456", "删除", "文件")
# 查看日志器信息
print("日志器信息:")
for logger_type, info in app_logger.get_all_loggers_info().items():
print(f" {logger_type}: {info}")
# 运行日志示例
print("=== 日志系统示例 ===")
demonstrate_logging()封装和抽象的最佳实践
推荐做法:
- 使用私有属性保护数据
- 提供清晰的公共接口
- 使用属性装饰器进行数据验证
- 实现适当的抽象层次
避免的做法:
- 暴露过多内部实现细节
- 创建过于复杂的接口
- 忽略数据验证
- 违反封装原则
高级封装特性
描述符
class ValidatedAttribute:
"""验证属性描述符"""
def __init__(self, min_value=None, max_value=None, allowed_values=None):
self.min_value = min_value
self.max_value = max_value
self.allowed_values = allowed_values
self.name = None
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
# 验证值
if self.allowed_values and value not in self.allowed_values:
raise ValueError(f"值必须是以下之一: {self.allowed_values}")
if self.min_value is not None and value < self.min_value:
raise ValueError(f"值不能小于 {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"值不能大于 {self.max_value}")
instance.__dict__[self.name] = value
class Person:
"""使用描述符的Person类"""
age = ValidatedAttribute(min_value=0, max_value=150)
grade = ValidatedAttribute(allowed_values=['A', 'B', 'C', 'D', 'F'])
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
# 使用描述符
person = Person("张三", 25, "A")
print(f"姓名: {person.name}, 年龄: {person.age}, 成绩: {person.grade}")
try:
person.age = -5 # 会抛出异常
except ValueError as e:
print(f"错误: {e}")
try:
person.grade = "X" # 会抛出异常
except ValueError as e:
print(f"错误: {e}")回顾
今天您学习了:
- 封装的基本概念和实现
- 属性装饰器的使用
- 抽象类和接口的概念
- 真实世界示例:数据库连接、日志系统
封装和抽象是面向对象编程的重要支柱,掌握这些概念将让您能够创建更加安全和易维护的代码!
相关推荐
- 安全教育登录入口平台(安全教育登录入口平台官网)
-
122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...
- 大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)
-
大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...
-
- 哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
-
要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...
-
2026-02-04 09:03 off999
- 电信宽带测速官网入口(电信宽带测速官网入口app)
-
这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...
- 植物大战僵尸95版手机下载(植物大战僵尸95 版下载)
-
1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...
- 免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)
-
1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...
- 2025世界杯赛程表(2025世界杯在哪个国家)
-
2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...
- 下载搜狐视频电视剧(搜狐电视剧下载安装)
-
搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...
- 永久免费听歌网站(丫丫音乐网)
-
可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...
- 音乐格式转换mp3软件(音乐格式转换器免费版)
-
有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...
- 电子书txt下载(免费的最全的小说阅读器)
-
1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...
- 最好免费观看高清电影(播放免费的最好看的电影)
-
在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...
- 孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)
-
要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
win7系统还原步骤图解(win7还原电脑系统的步骤)
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
16949认证费用是多少(16949审核员太难考了)
-
linux软件(linux软件图标)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
windows7旗舰版多少钱(win7旗舰版要多少钱)
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
