Python OOP小练习 - ATM模拟
复习一下Python面向对象编程,构建一个简单的ATM类,实现ATM自助取款机的模拟
这是一组渐进式的练习,从最简单的ATM类,到持久性数据保存,构成一系列适合初学者的练习
ATM - Automatic Trasaction Machine
简化模拟,只需要实现下面的一些功能:
1. 登录功能(这里简化,不需要实现)
2. 创建账户
3. 存钱
4. 取钱
5. 退出
第一个版本atm_v1.py
构建基本的ATM类,包含几个方法,初始化一个ATM实例,调用其方法
最主要的功能有存储账户信息、存钱、取钱; 账户信息使用Python 字典数据类型
class ATM:
def __init__(self):
self.accounts = {} # 用于存储账户信息的字典
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = initial_balance
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number] += amount
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number] >= amount:
self.accounts[account_number] -= amount
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在。")
# 测试ATM类
atm = ATM()
atm.create_account("123456789", 1000)
atm.deposit("123456789", 500)
atm.withdraw("123456789", 200)
print(atm.check_balance("123456789"))
第二个版本atm_v2.py
增加菜单,初始化ATM实例,一直运行,直到用户退出菜单,这个比较符合正常使用场景
增加几个方法:一个run方法让ATM一直执行,show_menu菜单
class ATM:
def __init__(self):
self.accounts = {}
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = initial_balance
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number] += amount
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number] >= amount:
self.accounts[account_number] -= amount
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在.")
def show_menu(self):
print("===== ATM菜单 =====")
print("1. 创建账户")
print("2. 查询余额")
print("3. 存款")
print("4. 取款")
print("0. 退出")
def run(self):
while True:
self.show_menu()
choice = input("请输入选项数字:")
if choice == "1":
account_number = input("请输入账户号码:")
initial_balance = float(input("请输入初始余额:"))
self.create_account(account_number, initial_balance)
elif choice == "2":
account_number = input("请输入账户号码:")
balance = self.check_balance(account_number)
if balance is not None:
print(f"账户 {account_number} 的余额为 {balance} 元。")
elif choice == "3":
account_number = input("请输入账户号码:")
amount = float(input("请输入存款金额:"))
self.deposit(account_number, amount)
elif choice == "4":
account_number = input("请输入账户号码:")
amount = float(input("请输入取款金额:"))
self.withdraw(account_number, amount)
elif choice == "0":
print("感谢使用ATM,再见!")
break
else:
print("无效选项,请重新输入。")
# 实例化ATM对象并运行
atm = ATM()
atm.run()
第三个版本 atm_v3.py
增加了历史记录存储
增加一个list变量 self.history,用来存储操作记录
class ATM:
def __init__(self):
self.accounts = {}
self.history = []
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = initial_balance
self.history.append(f"创建账户 {account_number},初始余额为 {initial_balance} 元。")
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number] += amount
self.history.append(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number] >= amount:
self.accounts[account_number] -= amount
self.history.append(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在.")
def show_history(self):
print("===== 操作历史记录 =====")
for entry in self.history:
print(entry)
print("======================")
def show_menu(self):
print("===== ATM菜单 =====")
print("1. 创建账户")
print("2. 查询余额")
print("3. 存款")
print("4. 取款")
print("5. 显示操作历史记录")
print("0. 退出")
def run(self):
while True:
self.show_menu()
choice = input("请输入选项数字:")
if choice == "1":
account_number = input("请输入账户号码:")
initial_balance = float(input("请输入初始余额:"))
self.create_account(account_number, initial_balance)
elif choice == "2":
account_number = input("请输入账户号码:")
balance = self.check_balance(account_number)
if balance is not None:
print(f"账户 {account_number} 的余额为 {balance} 元。")
elif choice == "3":
account_number = input("请输入账户号码:")
amount = float(input("请输入存款金额:"))
self.deposit(account_number, amount)
elif choice == "4":
account_number = input("请输入账户号码:")
amount = float(input("请输入取款金额:"))
self.withdraw(account_number, amount)
elif choice == "5":
self.show_history()
elif choice == "0":
print("感谢使用ATM,再见!")
break
else:
print("无效选项,请重新输入。")
# 实例化ATM对象并运行
atm = ATM()
atm.run()
第四个版本atm_v4.py
每个用户的历史记录单独存储
每个用户保存自己的历史记录,可以学习如何使用嵌套的数据类型,字典里面嵌套字典
将history变量放入账户变量self.accounts里面,这样每个账户单独保存各自的操作记录
class ATM:
def __init__(self):
self.accounts = {}
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = {
"balance": initial_balance,
"history": []
}
self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]["balance"]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number]["balance"] += amount
self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number]["balance"] >= amount:
self.accounts[account_number]["balance"] -= amount
self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在.")
def show_history(self, account_number):
if account_number in self.accounts:
print(f"===== 账户 {account_number} 操作历史记录 =====")
for entry in self.accounts[account_number]["history"]:
print(entry)
print("==============================")
else:
print("该账户不存在。")
def show_menu(self):
print("[===== ATM菜单 =====]")
print("1. 创建账户")
print("2. 查询余额")
print("3. 存款")
print("4. 取款")
print("5. 显示操作历史记录")
print("0. 退出")
def run(self):
while True:
self.show_menu()
choice = input("请输入选项数字:")
if choice == "1":
account_number = input("请输入账户号码:")
initial_balance = float(input("请输入初始余额:"))
self.create_account(account_number, initial_balance)
elif choice == "2":
account_number = input("请输入账户号码:")
balance = self.check_balance(account_number)
if balance is not None:
print(f"账户 {account_number} 的余额为 {balance} 元。")
elif choice == "3":
account_number = input("请输入账户号码:")
amount = float(input("请输入存款金额:"))
self.deposit(account_number, amount)
elif choice == "4":
account_number = input("请输入账户号码:")
amount = float(input("请输入取款金额:"))
self.withdraw(account_number, amount)
elif choice == "5":
account_number = input("请输入账户号码:")
self.show_history(account_number)
elif choice == "0":
print("感谢使用ATM,再见!")
break
else:
print("无效选项,请重新输入。")
# 实例化ATM对象并运行
atm = ATM()
atm.run()
继续进化...
第五个版本atm_v5.py
使用pickle持久存储数据,将账户信息保存到本地文件里面
pickle的中文资料,百度搜索
import pickle
class ATM:
def __init__(self):
self.accounts = {}
self.load_data() # 在初始化时加载之前保存的数据
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = {
"balance": initial_balance,
"history": []
}
self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]["balance"]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number]["balance"] += amount
self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number]["balance"] >= amount:
self.accounts[account_number]["balance"] -= amount
self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在.")
def show_history(self, account_number):
if account_number in self.accounts:
print(f"===== 账户 {account_number} 操作历史记录 =====")
for entry in self.accounts[account_number]["history"]:
print(entry)
print("==============================")
else:
print("该账户不存在。")
def show_menu(self):
print("[===== ATM菜单 =====]")
print("1. 创建账户")
print("2. 查询余额")
print("3. 存款")
print("4. 取款")
print("5. 显示操作历史记录")
print("0. 退出")
def load_data(self):
try:
with open("accounts_data.pickle", "rb") as file:
self.accounts = pickle.load(file)
except FileNotFoundError:
# 如果文件不存在,可以忽略此错误
pass
def save_data(self):
with open("accounts_data.pickle", "wb") as file:
pickle.dump(self.accounts, file)
def run(self):
while True:
self.show_menu()
choice = input("请输入选项数字:")
if choice == "1":
account_number = input("请输入账户号码:")
initial_balance = float(input("请输入初始余额:"))
self.create_account(account_number, initial_balance)
elif choice == "2":
account_number = input("请输入账户号码:")
balance = self.check_balance(account_number)
if balance is not None:
print(f"账户 {account_number} 的余额为 {balance} 元。")
elif choice == "3":
account_number = input("请输入账户号码:")
amount = float(input("请输入存款金额:"))
self.deposit(account_number, amount)
elif choice == "4":
account_number = input("请输入账户号码:")
amount = float(input("请输入取款金额:"))
self.withdraw(account_number, amount)
elif choice == "5":
account_number = input("请输入账户号码:")
self.show_history(account_number)
elif choice == "0":
self.save_data() # 在退出前保存数据
print("感谢使用ATM,再见!")
break
else:
print("无效选项,请重新输入。")
# 实例化ATM对象并运行
atm = ATM()
atm.run()
第六个版本atm_v4.py
使用加密库,对账户信息文件加密
使用cryptography库
如果没有安装,使用下面命令安装一下:pip install cryptography
from cryptography.fernet import Fernet
import pickle
import cryptography
import os
# 生成密钥并保存到文件中
def generate_key():
# 密钥文件路径
key_file_path = "secret.key"
# 检查文件是否存在,存在就不重新生成key
if os.path.exists(key_file_path) and os.path.isfile(key_file_path):
return
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
# 加载密钥
def load_key():
return open("secret.key", "rb").read()
# 加密数据
def encrypt_data(data, key):
f = Fernet(key)
return f.encrypt(data)
# 解密数据
def decrypt_data(encrypted_data, key):
f = Fernet(key)
return f.decrypt(encrypted_data)
class ATM:
def __init__(self):
self.accounts = {}
self.load_data() # 在初始化时加载之前保存的数据
def create_account(self, account_number, initial_balance):
if account_number not in self.accounts:
self.accounts[account_number] = {
"balance": initial_balance,
"history": []
}
self.accounts[account_number]["history"].append(f"创建账户,初始余额为 {initial_balance} 元。")
print(f"账户 {account_number} 创建成功,初始余额为 {initial_balance} 元。")
else:
print("该账户已存在。")
def check_balance(self, account_number):
if account_number in self.accounts:
return self.accounts[account_number]["balance"]
else:
print("该账户不存在。")
return None
def deposit(self, account_number, amount):
if account_number in self.accounts:
self.accounts[account_number]["balance"] += amount
self.accounts[account_number]["history"].append(f"存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"向账户 {account_number} 存入 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("该账户不存在。")
def withdraw(self, account_number, amount):
if account_number in self.accounts:
if self.accounts[account_number]["balance"] >= amount:
self.accounts[account_number]["balance"] -= amount
self.accounts[account_number]["history"].append(f"取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
print(f"从账户 {account_number} 取出 {amount} 元。当前余额为 {self.accounts[account_number]['balance']} 元。")
else:
print("余额不足,无法完成取款。")
else:
print("该账户不存在.")
def show_history(self, account_number):
if account_number in self.accounts:
print(f"===== 账户 {account_number} 操作历史记录 =====")
for entry in self.accounts[account_number]["history"]:
print(entry)
print("==============================")
else:
print("该账户不存在。")
def show_menu(self):
print("[===== ATM菜单 =====]")
print("1. 创建账户")
print("2. 查询余额")
print("3. 存款")
print("4. 取款")
print("5. 显示操作历史记录")
print("0. 退出")
def load_data(self):
try:
key = load_key()
with open("accounts_data.pickle", "rb") as file:
encrypted_data = file.read()
decrypted_data = decrypt_data(encrypted_data, key)
self.accounts = pickle.loads(decrypted_data)
except (FileNotFoundError, pickle.UnpicklingError, cryptography.fernet.InvalidToken):
# 如果文件不存在或解密失败,可以忽略此错误
print("fail to load data")
def save_data(self):
key = load_key()
data_to_save = pickle.dumps(self.accounts)
encrypted_data = encrypt_data(data_to_save, key)
with open("accounts_data.pickle", "wb") as file:
file.write(encrypted_data)
def run(self):
while True:
self.show_menu()
choice = input("请输入选项数字:")
if choice == "1":
account_number = input("请输入账户号码:")
initial_balance = float(input("请输入初始余额:"))
self.create_account(account_number, initial_balance)
elif choice == "2":
account_number = input("请输入账户号码:")
balance = self.check_balance(account_number)
if balance is not None:
print(f"账户 {account_number} 的余额为 {balance} 元。")
elif choice == "3":
account_number = input("请输入账户号码:")
amount = float(input("请输入存款金额:"))
self.deposit(account_number, amount)
elif choice == "4":
account_number = input("请输入账户号码:")
amount = float(input("请输入取款金额:"))
self.withdraw(account_number, amount)
elif choice == "5":
account_number = input("请输入账户号码:")
self.show_history(account_number)
elif choice == "0":
self.save_data() # 在退出前保存数据
print("感谢使用ATM,再见!")
break
else:
print("无效选项,请重新输入。")
# 生成密钥(仅需执行一次)
generate_key()
# 实例化ATM对象并运行
atm = ATM()
atm.run()
运行画面
[===== ATM菜单 =====]
1. 创建账户
2. 查询余额
3. 存款
4. 取款
5. 显示操作历史记录
0. 退出
请输入选项数字: