Python教程(二十四):封装和抽象
off999 2025-08-01 20:05 87 浏览 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}")回顾
今天您学习了:
- 封装的基本概念和实现
- 属性装饰器的使用
- 抽象类和接口的概念
- 真实世界示例:数据库连接、日志系统
封装和抽象是面向对象编程的重要支柱,掌握这些概念将让您能够创建更加安全和易维护的代码!
相关推荐
- tplogin管理员登录入口(tplogin重新设置密码)
-
tplogin.cn是新版tplink路由器的登录地址(管理页面地址),在浏览器中输入tplogin.cn,就可以打开tplink路由器的管理页面(登录页面)。具体的登录方法如下:1、打开电脑上的浏...
- psp模拟器怎么导入游戏(psp模拟器怎么导入游戏 Vivo手机)
-
方法如下:1、打开能操作文件的助手软件,用pp链接后点击左下文件,然后点常用目录下的程序用户,会出现ppsspp的文件夹。2、打开ppsspp文件夹,会出来四个选项文件夹,第一个进去后是psp文件夹,...
- 电脑系统怎样升级(电脑系统怎么升级)
-
电脑系统升级方法步骤,1、打开电脑,点击电脑左下角的开始菜单,在弹出的菜单选项中选择“控制面板”。2、点击“开始”,点击“控制面板”3、在控制面板中,点击“系统和安全”。4、点击启用或禁用自动更新。5...
- windows无法激活(windows无法激活有什么影响)
-
1.如果修复或重新组装了电脑,则可能是安装了不同版本的Windows。或者,如果在修复过程中为电脑使用了其他产品密钥,当使用该密钥的电脑数大于Microsoft软件许可条款允许的电脑数时,该密钥...
-
- u盘文件恢复软件免费(恢复u盘数据免费的软件)
-
u盘损坏文件恢复方法:1、打开电脑桌面的“计算机”或“我的电脑”。2、然后再找到需要修复的u盘。3、打开“运行”窗口(可以直接按“Windows+R”快捷打开),输入“CMD”并点击“确定”按钮以进入命令提符界面。4、从打开的“命令提示符”...
-
2025-12-28 22:03 off999
- 电脑uac是什么意思
-
UAC就是用户帐户控制,在对计算机进行更改之前,用户帐户控制(UAC)会通知您。比如安装软件驱动什么的,默认UAC设置会在程序尝试对计算机进行更改时通知您,但您可以通过调整设置来控制UAC...
- 笔记本找不到自己家的wifi怎么办
-
1.笔记本电脑缺少无线网卡驱动,需要下载驱动如果笔记本电脑开机之后,无法显示WiFi网络的图标,这个时候多半是因为电脑缺少无线网卡驱动造成的,有时候自己在清理电脑的时候,不小心清理了驱动程序,便会...
- 电信宽带办理电话是多少(电信宽带办理联系电话)
-
电信宽带不一定需要电信手机号码,可以根据自身需要选择,有单独的宽带业务,一般要求预存一定时间的使用费。不过一般包含了宽带、手机号码的融合套餐总体上更优惠,对客户来说更划算。如果有相应需求的话,建议同时...
- 开机进入ghost启动项(电脑启动进入ghost)
-
电脑启动的时候进入GHOST界面方法: 1、首先确认电脑装了GHOST软件。 2、重启电脑,注意仔细观察电脑屏幕,会有一个3s或者10s的选择界面。让选择是进入GHOST界面,或者正常启动进入系...
- 华硕bios修复蓝屏图解(华硕bios修复蓝屏视频教程)
-
先看下BIOS是否可以识别到硬盘设备,若看不到,硬盘故障的可能性很大。若可以看到硬盘,建议先尝试进行BIOS兼容性设置:1,在BIOS界面,通过方向键进【Secure】菜单,通过方向键选择【Sec...
- 老电脑怎么装win7系统(老电脑装win7系统可以吗)
-
6年前的电脑,如果是用的当时最新的CPU的话,应该是第7代或者第6代酷睿等级的。运行windows7和windows10都应该没有压力。从软件的兼容性来说,还是建议安装windows10,因为现在有好...
- 电脑怎么设置到点自动关机(电脑怎样设置到点关机)
-
1、首先我们点击电脑屏幕左下角的开始按钮,在所有程序里依次选择附件---系统工具,接着打开任务计划程序。2、我们打开任务计划程序后,在最右边的操作框里选择创建基本任务,然后在创建基本任务对话框的名称一...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
- 最近发表
- 标签列表
-
- 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)
