第7章 7.5 综合实战:银行账户管理系统
🎯 开场:为什么你的钱包需要「面向对象」?
上一章我们学会了用类方法来组织代码,还记得那个「会自我描述」的 __str__ 吗?那一章的结尾我留了个小悬念:如果把这些方法组合起来,能做一个真正能用的东西吗?
答案是:能,而且做一个银行账户系统,比你想象的简单得多。
你有没有遇到过这种情况——月底对着银行短信发愁:「我到底花了多少钱?还剩多少?转给朋友的钱到账了没?」这些需求听起来很复杂,但其实就是一个账户管理器该干的事。
今天我们就用 Python 的面向对象,把这些功能全部实现出来。学完这章,你会有一个真正能跑起来的银行账户管理系统,而且还能加利息、算年费、做对账——这些功能下一章讲 collections 的时候会用到,到时候你会发现数据结构选对了,事半功倍。
🧱 基础:银行账户的「类」设计
什么是银行账户?生活类比
想象你去银行开户。柜员会让你填一张表,这张表上有什么?
- 账号(唯一标识,相当于你的身份证号)
- 户名(你的名字)
- 余额(你存了多少钱)
- 开户时间(什么时候开的户)
每次你存款,余额就增加;取款,余额就减少;转账,就是你少了他多了。这些动作,在代码里就是方法。
说白了:一个银行账户 = 数据(账号、余额)+ 行为(存钱、取钱、转账)
这不就是我们一直在学的「类」吗?
第一个账户类
先来看一个最简单版本:
class BankAccount:
"""银行账户类"""
def __init__(self, account_id, owner_name, initial_balance=0):
"""开户:创建账户时需要账号、户名、初始存款"""
self.account_id = account_id # 账号
self.owner_name = owner_name # 户名
self.balance = initial_balance # 余额
self.transaction_history = [] # 交易记录
print(f"开户成功!账号 {account_id},户名 {owner_name},存入 {initial_balance} 元")
def deposit(self, amount):
"""存款:余额增加"""
if amount <= 0:
print("存款金额必须大于0")
return False
self.balance += amount
self.transaction_history.append(f"存款 +{amount}")
print(f"存款成功!当前余额:{self.balance} 元")
return True
def withdraw(self, amount):
"""取款:余额减少"""
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
self.balance -= amount
self.transaction_history.append(f"取款 -{amount}")
print(f"取款成功!当前余额:{self.balance} 元")
return True
def get_balance(self):
"""查询余额"""
return self.balance
def __str__(self):
"""打印账户信息"""
return f"账号:{self.account_id},户名:{self.owner_name},余额:{self.balance} 元"
# 创建一个账户
account = BankAccount("001", "张三", 1000)
print(account)
输出:
开户成功!账号 001,户名 张三,存入 1000 元
账号:001,户名:张三,余额:1000 元
这段代码做了啥?
- __init__ 就是「开户」动作,创建账户时自动执行
- deposit 和 withdraw 是存钱取钱,存钱加余额,取钱减余额
- get_balance 返回当前余额
- transaction_history 记录了每一笔交易,像银行的对账单
为什么要用魔术方法 __str__?
看最后两行代码:
print(account) # 用 print 打印对象
如果没有 __str__,print 会输出类似 <__main__.BankAccount object at 0x...> 这种看不懂的东西。有了 __str__,打印出来就是人类能读懂的信息。
类比:这就像银行的存折封面,有了它你一眼就知道「这是我的账户」而不是「这是一个银行对象」。

再加一个转账功能
两个人之间转钱,代码怎么写?
def transfer(self, target_account, amount):
"""转账:从本账户转钱到目标账户"""
if amount <= 0:
print("转账金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
# 本账户扣钱
self.balance -= amount
self.transaction_history.append(f"转出 -{amount} 至 {target_account.account_id}")
# 目标账户加钱
target_account.balance += amount
target_account.transaction_history.append(f"转入 +{amount} 来自 {self.account_id}")
print(f"转账成功!向 {target_account.owner_name} 转账 {amount} 元")
return True
这段代码的关键点:
- 转账是两个账户之间的事,所以需要 target_account 参数(另一个 BankAccount 对象)
- 本账户余额减少,目标账户余额增加,这两件事必须同时发生
- 双方都记录交易历史,方便对账
🔥 实战:三个项目递进做
项目 1:5 分钟搞定基础账户操作
跟着抄,就能跑:
class BankAccount:
def __init__(self, account_id, owner_name, initial_balance=0):
self.account_id = account_id
self.owner_name = owner_name
self.balance = initial_balance
self.transaction_history = []
print(f"开户成功!账号 {account_id},户名 {owner_name},存入 {initial_balance} 元")
def deposit(self, amount):
if amount <= 0:
print("存款金额必须大于0")
return False
self.balance += amount
self.transaction_history.append(f"存款 +{amount}")
print(f"存款成功!当前余额:{self.balance} 元")
return True
def withdraw(self, amount):
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
self.balance -= amount
self.transaction_history.append(f"取款 -{amount}")
print(f"取款成功!当前余额:{self.balance} 元")
return True
def transfer(self, target_account, amount):
if amount <= 0:
print("转账金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
self.balance -= amount
self.transaction_history.append(f"转出 -{amount} 至 {target_account.account_id}")
target_account.balance += amount
target_account.transaction_history.append(f"转入 +{amount} 来自 {self.account_id}")
print(f"转账成功!向 {target_account.owner_name} 转账 {amount} 元")
return True
def get_history(self):
"""查看交易历史"""
return self.transaction_history
def __str__(self):
return f"账号:{self.account_id},户名:{self.owner_name},余额:{self.balance} 元"
# 小明的账户
xiaoming = BankAccount("001", "小明", 5000)
print(xiaoming)
# 小红开户
xiaohong = BankAccount("002", "小红", 2000)
print(xiaohong)
# 小明存款1000
xiaoming.deposit(1000)
# 小红取款500
xiaohong.withdraw(500)
# 小明转账2000给小红
xiaoming.transfer(xiaohong, 2000)
# 查看交易历史
print(f"\n小明的交易记录:{xiaoming.get_history()}")
print(f"小红的交易记录:{xiaohong.get_history()}")
print(f"\n最终余额:小明 {xiaoming.balance} 元,小红 {xiaohong.balance} 元")
输出:
开户成功!账号 001,户名 小明,存入 5000 元
账号:001,户名:小明,余额:5000 元
开户成功!账号 002,户名 小红,存入 2000 元
账号:002,户名:小红,余额:2000 元
存款成功!当前余额:6000 元
取款成功!当前余额:1500 元
转账成功!向 小红 转账 2000 元
小明的交易记录:['存款 +1000', '转出 -2000 至 002']
小红的交易记录:['取款 -500', '转入 +2000 来自 001']
最终余额:小明 4000 元,小红 3500 元
一句话解释:小明原来5000,存了1000变6000,转出2000给小红了,最后剩4000。小红原来2000,取了500变1500,收到2000变3500。
项目 2:加上利息和年费(15 分钟)
真实银行会干嘛?利息!存款给利息,年费!管理账户要收钱。
class BankAccount:
def __init__(self, account_id, owner_name, initial_balance=0, annual_fee=0):
self.account_id = account_id
self.owner_name = owner_name
self.balance = initial_balance
self.transaction_history = []
self.annual_fee = annual_fee # 年费
self.interest_rate = 0.035 # 年利率 3.5%
self.creation_date = "2024-01-01" # 简化处理,实际应该用 datetime
def deposit(self, amount):
if amount <= 0:
print("存款金额必须大于0")
return False
self.balance += amount
self.transaction_history.append(f"存款 +{amount}")
print(f"存款成功!当前余额:{self.balance} 元")
return True
def withdraw(self, amount):
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
self.balance -= amount
self.transaction_history.append(f"取款 -{amount}")
print(f"取款成功!当前余额:{self.balance} 元")
return True
def transfer(self, target_account, amount):
if amount <= 0:
print("转账金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance} 元")
return False
self.balance -= amount
self.transaction_history.append(f"转出 -{amount} 至 {target_account.account_id}")
target_account.balance += amount
target_account.transaction_history.append(f"转入 +{amount} 来自 {self.account_id}")
print(f"转账成功!向 {target_account.owner_name} 转账 {amount} 元")
return True
def calculate_interest(self, months):
"""计算利息:按月计算,简化版"""
monthly_rate = self.interest_rate / 12
interest = self.balance * monthly_rate * months
print(f"存款 {self.balance} 元,利率 {self.interest_rate*100}%,{months} 个月利息:{interest:.2f} 元")
return interest
def apply_interest(self, months):
"""发放利息:余额增加"""
interest = self.calculate_interest(months)
self.balance += interest
self.transaction_history.append(f"利息 +{interest:.2f}")
print(f"利息已发放!当前余额:{self.balance:.2f} 元")
return interest
def charge_annual_fee(self):
"""扣除年费"""
if self.annual_fee > 0:
if self.balance >= self.annual_fee:
self.balance -= self.annual_fee
self.transaction_history.append(f"年费 -{self.annual_fee}")
print(f"年费 {self.annual_fee} 元已扣除,当前余额:{self.balance} 元")
else:
print(f"余额不足,无法扣除年费 {self.annual_fee} 元")
def get_balance(self):
return self.balance
def get_history(self):
return self.transaction_history
def monthly_statement(self):
"""月度对账单"""
print(f"\n===== {self.account_id} {self.owner_name} 对账单 =====")
print(f"当前余额:{self.balance:.2f} 元")
print(f"年利率:{self.interest_rate*100}%")
print(f"年费:{self.annual_fee} 元")
print("交易记录:")
for record in self.transaction_history:
print(f" - {record}")
print("=" * 35)
def __str__(self):
return f"账号:{self.account_id},户名:{self.owner_name},余额:{self.balance:.2f} 元"
# 创建账户:小明存1万,小红存5千,小明要交年费
xiaoming = BankAccount("001", "小明", 10000, annual_fee=100)
xiaohong = BankAccount("002", "小红", 5000, annual_fee=0)
print("\n--- 3个月后的操作 ---")
# 小明存了3个月,拿利息
xiaoming.apply_interest(3)
# 小红也存了3个月
xiaohong.apply_interest(3)
print("\n--- 扣除年费 ---")
xiaoming.charge_annual_fee()
xiaohong.charge_annual_fee()
print("\n--- 月度对账单 ---")
xiaoming.monthly_statement()
xiaohong.monthly_statement()
输出:
开户成功!账号 001,户名 小明,存入 10000 元
开户成功!账号 002,户名 小红,存入 5000 元
--- 3个月后的操作 ---
存款 10000 元,利率 3.5%,3 个月利息:87.50 元
利息已发放!当前余额:10087.50 元
存款 5000 元,利率 3.5%,3 个月利息:43.75 元
利息已发放!当前余额:5043.75 元
--- 扣除年费 ---
年费 100 元已扣除,当前余额:9987.50 元
余额不足,无法扣除年费 0 元
===== 001 小明 对账单 =====
当前余额:9987.50 元
年利率:3.5%
年费:100 元
交易记录:
- 利息 +87.50
- 年费 -100
===================================
===== 002 小红 对账单 =====
当前余额:5043.75 元
年利率:3.5%
年费:0 元
交易记录:
- 利息 +43.75
===================================
一句话解释:小明存了1万,3个月利息87.5元,扣掉100元年费,最后剩9987.5元。小红没年费,利息43.75元,最后5043.75元。

项目 3:做个银行系统管理器(15 分钟)
现在我们有很多账户了,需要一个银行系统来管理它们。想象你是银行柜员,手里有很多账户,要能:
- 开户
- 销户
- 查找账户
- 批量操作
class BankSystem:
"""银行系统:管理所有账户"""
def __init__(self, bank_name):
self.bank_name = bank_name
self.accounts = {} # 用字典存储,key是账号,value是账户对象
print(f"🏦 {bank_name} 系统初始化完成")
def open_account(self, account_id, owner_name, initial_balance=0, annual_fee=0):
"""开户"""
if account_id in self.accounts:
print(f"账号 {account_id} 已存在!")
return None
account = BankAccount(account_id, owner_name, initial_balance, annual_fee)
self.accounts[account_id] = account
print(f"✅ 开户成功!当前账户数:{len(self.accounts)}")
return account
def close_account(self, account_id):
"""销户"""
if account_id not in self.accounts:
print(f"账号 {account_id} 不存在!")
return False
account = self.accounts[account_id]
print(f"⚠️ 销户警告:账号 {account_id}({account.owner_name})即将注销")
print(f" 最终余额:{account.balance} 元")
del self.accounts[account_id]
print(f"✅ 销户成功!当前账户数:{len(self.accounts)}")
return True
def find_account(self, account_id):
"""查找账户"""
return self.accounts.get(account_id, None)
def show_all_accounts(self):
"""显示所有账户"""
print(f"\n🏦 {self.bank_name} - 所有账户")
print("=" * 40)
for account in self.accounts.values():
print(account)
print(f"共 {len(self.accounts)} 个账户")
print("=" * 40)
def get_total_deposits(self):
"""计算银行总存款"""
total = sum(account.balance for account in self.accounts.values())
print(f"📊 银行总存款:{total:.2f} 元,共 {len(self.accounts)} 个账户")
return total
def batch_interest(self, months):
"""批量发放利息"""
print(f"\n📋 批量发放 {months} 个月利息")
for account in self.accounts.values():
account.apply_interest(months)
def transfer_between_accounts(self, from_id, to_id, amount):
"""行内转账"""
from_account = self.find_account(from_id)
to_account = self.find_account(to_id)
if not from_account:
print(f"转出账号 {from_id} 不存在!")
return False
if not to_account:
print(f"转入账号 {to_id} 不存在!")
return False
return from_account.transfer(to_account, amount)
# 创建一个银行系统
icbc = BankSystem("宇宙银行")
print("\n=== 开户 ===")
icbc.open_account("001", "小明", 10000, annual_fee=100)
icbc.open_account("002", "小红", 5000)
icbc.open_account("003", "小刚", 20000, annual_fee=50)
print("\n=== 查看所有账户 ===")
icbc.show_all_accounts()
print("\n=== 行内转账 ===")
icbc.transfer_between_accounts("001", "002", 3000)
print("\n=== 查找账户 ===")
account = icbc.find_account("002")
if account:
print(f"找到:{account}")
print("\n=== 批量发利息 ===")
icbc.batch_interest(6)
print("\n=== 统计 ===")
icbc.get_total_deposits()
print("\n=== 销户 ===")
icbc.close_account("003")
print("\n=== 最终账户列表 ===")
icbc.show_all_accounts()
输出:
🏦 宇宙银行 系统初始化完成
=== 开户 ===
开户成功!账号 001,户名 小明,存入 10000 元
✅ 开户成功!当前账户数:1
开户成功!账号 002,户名 小红,存入 5000 元
✅ 开户成功!当前账户数:2
开户成功!账号 003,户名 小刚,存入 20000 元
✅ 开户成功!当前账户数:3
=== 查看所有账户 ===
🏦 宇宙银行 - 所有账户
========================================
账号:001,户名:小明,余额:10000.00 元
账号:002,户名:小红,余额:5000.00 元
账号:003,户名:小刚,余额:20000.00 元
共 3 个账户
========================================
=== 行内转账 ===
转账成功!向 小红 转账 3000 元
=== 查找账户 ===
找到:账号:002,户名:小红,余额:8000.00 元
=== 批量发利息 ===
📋 批量发放 6 个月利息
存款 7000.00 元,利率 3.5%,6 个月利息:122.50 元
利息已发放!当前余额:7122.50 元
存款 8000.00 元,利率 3.5%,6 个月利息:140.00 元
利息已发放!当前余额:8140.00 元
📊 银行总存款:35122.50 元,共 3 个账户
=== 销户 ===
⚠️ 销户警告:账号 003(小刚)即将注销
终余额:20512.50 元
✅ 销户成功!当前账户数:2
=== 最终账户列表 ===
🏦 宇宙银行 - 所有账户
========================================
账号:001,户名:小明,余额:7122.50 元
账号:002,户名:小红,余额:8140.00 元
共 2 个账户
========================================
一句话解释:银行系统就像一个 Excel 表格,accounts 字典是表格内容,账号是行号,每个账户是表格里的一行数据。批量操作就是对这个表格的所有行做同样的事。
💪 进阶:新手最容易踩的坑
坑 1:余额为负数!
❌ 错误示例:
xiaoming = BankAccount("001", "小明", 100)
xiaoming.withdraw(200) # 余额只有100,取200
print(f"余额:{xiaoming.balance}") # 余额变成 -100 了!
✅ 正确做法:加一个余额检查,像项目里的代码那样。
坑 2:转账时忘记更新两个账户
❌ 错误示例:
def transfer(self, target_account, amount):
self.balance -= amount
# 忘记给 target_account 加钱了!
print("转账完成")
✅ 正确做法:
def transfer(self, target_account, amount):
self.balance -= amount
target_account.balance += amount # 两个账户都要更新
坑 3:年费扣除时机不对
如果账户余额只有50元年费100,扣完变负数了,银行会怎么做?
✅ 正确做法:先检查余额够不够,不够就不扣。
def charge_annual_fee(self):
if self.balance >= self.annual_fee: # 先检查!
self.balance -= self.annual_fee
坑 4:用可变对象做默认参数
❌ 危险示例:
class BadExample:
def __init__(self, name, history=[]): # 坑!默认参数是可变对象
self.name = name
self.history = history
✅ 正确做法:
class GoodExample:
def __init__(self, name, history=None):
self.name = name
self.history = history if history is not None else [] # 用 None 做默认值
坑 5:忘记 self 是谁
❌ 错误示例:
def deposit(self, amount):
balance += amount # 忘了加 self.balance
✅ 正确做法:
def deposit(self, amount):
self.balance += amount # 记得加 self
调试技巧:加日志
代码出问题怎么办?加 print 大法:
def withdraw(self, amount):
print(f"[DEBUG] 取款前余额:{self.balance},取款金额:{amount}")
if amount > self.balance:
print(f"[ERROR] 余额不足!")
return False
self.balance -= amount
print(f"[DEBUG] 取款后余额:{self.balance}")
return True
✏️ 练习题
练习 1(2 分钟):开户就能用
- 输入:运行代码创建账户,初始存款 8888 元
- 预期输出:打印「开户成功!账号 001,户名 小明,存入 8888 元」
- 提示:直接改
initial_balance参数就行
练习 2(2 分钟):余额不足时取款
- 输入:账户余额 100,取款 200
- 预期输出:「余额不足!当前余额:100 元」
- 提示:看看
withdraw方法里的 if 判断
练习 3(3 分钟):计算半年利息
- 输入:存款 10000 元,年利率 3.5%,存 6 个月
- 预期输出:利息 175 元
- 提示:用
calculate_interest(6)方法
练习 4(5 分钟):改写转账方法
- 输入:在转账成功后,增加一条打印「交易完成,流水号 XXX」
- 预期输出:转账时能看到「交易完成」字样
- 提示:在
transfer方法里加一行print
练习 5(5 分钟):分析报错
- 输入:运行下面这段代码
account = BankAccount("001", "测试", 1000)
account.withdraw(500)
print(account.balance)
- 预期输出:报错
AttributeError: 'BankAccount' object has no attribute 'balance' - 提示:检查
__init__方法里余额是怎么存的
作业:做一个「个人财务小管家」
需求描述:
做一个命令行工具,管理你的个人财务。支持以下功能:
功能点:
1. 记账:记录收入和支出,自动计算余额
2. 统计:显示本月收入总额、支出总额、结余
3. 导出:把交易记录导出成文本文件
加分项(选做):
1. 支持多账户管理(工资卡、零花钱卡)
2. 支持月份查询(查指定月份的花销)
验收标准:
- 能跑起来
- 输入命令能显示正确结果
- 代码有中文注释
提交方式:评论区贴代码或 GitHub 链接
📚 总结
今天我们用银行账户这个生活场景,完整实践了面向对象的三大核心:
- 类是蓝图——像建筑图纸,定义了账户有什么(数据)和能做什么(方法)
- 实例是产品——按图纸盖出来的房子,每个账户都是独立的
- 魔术方法是自动化——
__init__自动开户,__str__自动打印信息
这些概念看似简单,但下一章的 collections 高级数据结构 会用到——到时候你会发现,银行系统里存的那些账户,用列表还是字典效率差很多,选对了数据结构,做什么都快。
你在生活中有没有需要「管理一堆东西」的场景? 比如收藏夹管理、购物车、联系人……评论区聊聊,下一章我们会用 collections 优化这些问题!
延伸学习资源:
- 📖 官方文档:https://docs.python.org/zh-cn/3/tutorial/classes.html
- 📖 《Python编程:从入门到实践》第 9 章「类」
- 🎬 B站小甲鱼《Python教程》第 38-42 讲

评论(0)