Python ATM实战
1 ATM实战项目说明文档
模拟实现银行ATM机的操作系统,完整项目见资源https://download.csdn.net/download/weixin_44410704/85191854
1.1 项目基本功能
ATM系统主要功能:(要求使用类实现)
- 1.注册:用户名、手机号、身份证号、密码(两次确认,长度6位)
- 2.查询:账号必须存在,密码(三次机会,不对就锁卡)
- 3.取款:账号必须存在,密码(三次机会,不对就锁卡),取款金额不能大于存款
- 4.存款:账号必须存在,密码(三次机会,不对就锁卡),存款金额不能低于0
- 5.转账:两个账户都必须存在,密码(三次机会,不对就锁卡),转账金额不能超过余额
- 6.锁卡:账号存在,可以使用密码/身份证号冻结
- 7.解卡:账号存在,只能使用身份证号解卡
- 8.补卡:使用身份证补卡,每个身份证只有一张卡,之前的卡作废
- 9.改密:账号存在,使用原密码/身份证号改密
- 0.退出:保存数据
1.2 项目基本结构
ATM/
│ main.py
│ README.md
│
├─databases
│ cardid.txt
│ userid.txt
│ __init__.py
│
├─packages
│ │ cardclass.py
│ │ controllerclass.py
│ │ personclass.py
│ │ viewclass.py
│ └─__init__.py
│
└─Transaction_records100001.txt100002.txt__init__.py
1.3 运行环境
- 系统:windows
- 版本:python 3.9+
- 其他:无
1.4 待开发功能(已开发)
给当前ATM增加一个交易记录的功能(存折),每次金额变动都存储下来
记录的格式:
- [日期 时间]存款200元,余额300元
- [日期 时间]转账 向用户:张三,卡号:******转账100元,余额200元
1.5 项目开发流程(学习用)
- (1)定义各个类(属性写完整)—方法实现框架即可(可先不写详细)
- (2)实现main
- (3)详细定义类中的方法
1.6 项目代码
main.py
"""
ATM系统主要功能:(要求使用类实现)1.注册:用户名、手机号、身份证号、密码(两次确认,长度6位)2.查询:账号必须存在,密码(三次机会,不对就锁卡)3.取款:账号必须存在,密码(三次机会,不对就锁卡),取款金额不能大于存款4.存款:账号必须存在,密码(三次机会,不对就锁卡),存款金额不能低于05.转账:两个账户都必须存在,密码(三次机会,不对就锁卡),转账金额不能超过余额6.锁卡:账号存在,可以使用密码/身份证号冻结7.解卡:账号存在,只能使用身份证号解卡8.补卡:使用身份证补卡,每个身份证只有一张卡,之前的卡作废9.改密:账号存在,使用原密码/身份证号改密0.退出:保存数据
扩展功能:给当前ATM增加一个交易记录的功能(存折),每次金额变动都存储下来记录的格式:[日期 时间]存款200元,余额300元[日期 时间]转账 向用户:张三,卡号:******转账100元,余额200元
项目分析:
思考需要那些对象?类:1.银行卡:Card卡号: cardid密码: password余额: money是否锁卡: islock2.用户对象: Person用户名: name身份证号: userid手机号: phoneNumber卡: Card 银行卡对象3.控制器对象:Controller 具体的操作控制类1.注册:register2.查询:query3.取款:withdraw4.存款:deposit5.转账:transfer6.锁卡:lock7.解卡:unlock8.补卡:new_card9.改密:change_pwd0.退出:exit4.视图对象:Views(欢迎界面,操作界面)
思考如何存储数据?文件存储:卡号:用户==>user.txt身份证:==>userid.txt
"""
from packages.viewclass import Views
from packages.controllerclass import Controller
import timeclass main:def __init__(self):view = Views()obj = Controller()while True:num = input("请输入您需要使用的操作:")if num == '1':obj.register()time.sleep(2)view.show_operator()elif num == '2':obj.query()time.sleep(2)view.show_operator()elif num == '3':obj.withdraw()time.sleep(2)view.show_operator()elif num == '4':obj.deposit()time.sleep(2)view.show_operator()elif num == '5':obj.transfer()time.sleep(2)view.show_operator()elif num == '6':obj.lock('b')time.sleep(2)view.show_operator()elif num == '7':obj.unlock()time.sleep(2)view.show_operator()elif num == '8':obj.new_card()time.sleep(2)view.show_operator()elif num == '9':obj.change_pwd()time.sleep(2)view.show_operator()elif num == '0':obj.store()breakelse:print("您的输入有误,请重新输入:")view.show_operator()run = main()
cardclass.py
class Card:def __init__(self,cardid,pwd,islock=False,money=10):self.password = pwd # 密码self.money = money # 余额self.islock = islock # 卡号是否已锁,True表示已锁,False表示未锁self.cardid = cardid # 卡号
controllerclass.py
from packages.cardclass import Card
from packages.personclass import Person
import os
import pickle
import timeclass Controller:def __init__(self):# 以下列表中,每个用户的相关信息的索引是一样的,比如用户1的个人信息在personlist[1]中,则其卡信息在cardlist[1]中,# 卡号在cardidlist[1]中,身份证号在useridlist[1]中,姓名在namelist[1]中,即相关信息的索引都是1self.personlist = [] # 存储所有的用户,Person类的实现self.cardlist = [] # 存储所有的卡,Card的实现self.cardidlist = [] # 存储所有的卡号self.namelist = [] # 存储所有的姓名self.useridlist = [] # 存储所有的身份证号self.data_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'] # 就是存储一个字典,方便检查某个输入输入是否为数字# 读取userid.txt中的数据,将其存储到相应的列表中if os.path.getsize('./databases/userid.txt') > 0:with open('./databases/userid.txt', 'rb') as fp:try:while True:self.personlist = pickle.load(fp) # 这里就是为了读出所有的对象except EOFError: # 就是防止对象读完之后报错EOFErrorfor i in self.personlist:self.namelist.append(i.name)self.useridlist.append(i.userid)# 读取cardid.txt中的数据,将其存储到相应的列表中if os.path.getsize('./databases/cardid.txt') > 0:with open('./databases/cardid.txt', 'rb') as fp:try:while True:self.cardlist = pickle.load(fp) # 这里就是为了读出所有的对象except EOFError: # 就是防止对象读完之后报错EOFErrorfor i in self.cardlist:self.cardidlist.append(i.cardid)def register(self):name = self.__getusername()userid = self.__getuserid()phoneNumber = self.__getphoneNumber()cardid = 100000 + len(self.personlist) # 第一个卡号为100000,后面每增加一个用户,卡号增加1while str(cardid) in self.cardidlist: # 由于换卡的存在,增加用户卡号增加1会导致卡号相同,为了避免这种情况出现而设置的机制cardid += 1cardid = str(cardid)pwd = self.__getpassword()person = Person(name, userid, phoneNumber, cardid)card = Card(cardid, pwd)self.cardlist.append(card) # 注册一个用户就将其信息添加到相应的信息列表中self.personlist.append(person)self.namelist.append(name)self.useridlist.append(userid)self.cardidlist.append(cardid)print(f"注册成功,卡号为{cardid}")self.store() # 注册一个用户就存储,保证用户信息存储到对应的.txt文件中def query(self):idx = self.login() # 这个函数是起到登录的作用if idx != 'a':print(f"卡号:{self.cardlist[idx].cardid},余额:{self.cardlist[idx].money}")def withdraw(self):idx = self.login()if idx != 'a':while True:num = int(input("请输入取出金额:"))if num > self.cardlist[idx].money:print("取出金额不可大于余额!")continueelse:if self.input_pwd(self.cardidlist[idx]): # 这个函数检查输入的密码是否正确self.cardlist[idx].money -= numprint(f"卡号:{self.cardlist[idx].cardid},余额:{self.cardlist[idx].money}")file_url = f'./Transaction_records/{self.cardlist[idx].cardid}.txt'content = time.strftime('%Y-%m-%d %H:%M:%S') + f'##卡号:{self.cardlist[idx].cardid},取款:{num}元,余额:{self.cardlist[idx].money}元\n'with open(file_url, 'a+',encoding='utf-8') as fp:fp.write(content)self.store() # 取款后就就存储,保证用户信息更新到对应的.txt文件中breakelse:print("转账失败!")breakdef deposit(self):idx = self.login()if idx != 'a':while True:num = int(input("请输入存储金额:"))if self.input_pwd(self.cardidlist[idx]):self.cardlist[idx].money += numprint(f"卡号:{self.cardlist[idx].cardid},余额:{self.cardlist[idx].money}")file_url = f'./Transaction_records/{self.cardlist[idx].cardid}.txt'content = time.strftime('%Y-%m-%d %H:%M:%S') + f'##卡号:{self.cardlist[idx].cardid},存款:{num}元,余额:{self.cardlist[idx].money}元\n'with open(file_url, 'a+', encoding='utf-8') as fp:fp.write(content)self.store() # 存款后就就存储,保证用户信息更新到对应的.txt文件中breakelse:print("存储失败!")breakdef transfer(self):idx = self.login()if idx != 'a':flag = 1while flag:cardid = input("请输入转账卡号:")if cardid not in self.cardidlist:print("卡号不存在,请重新输入卡号!")continueelse:trfr_idx = self.cardidlist.index(cardid)while True:num = int(input("请输入转账金额:"))if num > self.cardlist[idx].money:print("转账金额不可大于余额!")continueelse:if self.input_pwd(self.cardidlist[idx]):self.cardlist[idx].money -= numself.cardlist[trfr_idx].money += numprint(f"卡号:{self.cardlist[idx].cardid},余额:{self.cardlist[idx].money}")self.store()flag = 0file_url = f'./Transaction_records/{self.cardlist[idx].cardid}.txt'content = time.strftime('%Y-%m-%d %H:%M:%S') + f'##卡号:{self.cardlist[idx].cardid},转账:{num}元,余额:{self.cardlist[idx].money}元\n'with open(file_url, 'a+', encoding='utf-8') as fp:fp.write(content)breakelse:print("密码错误,转账失败!")breakdef lock(self,idx):if idx == 'b':print("不可主动锁卡")else:self.cardlist[idx].islock = Trueself.store()def unlock(self): # 需要提供身份证号和卡号才可解卡flag = 1while flag:userid = input("请输入身份证号:")if userid not in self.useridlist:print("身份证号不存在,请重新输入!")continueelse:while True:cardid = input("请输入卡号:")if cardid not in self.cardidlist:print("卡号不存在,请重新输入!")continueelse:if self.useridlist.index(userid) != self.cardidlist.index(cardid):print("身份证号和卡号不匹配,解卡失败!")else:self.cardlist[self.useridlist.index(userid)].islock = Falseprint("解卡成功!")self.store()flag = 0breakdef new_card(self): # 需要输入姓名和身份证号才可补卡flag = 1while flag:name = input("请输入姓名:")if name not in self.namelist:print("姓名不存在,请重新输入!")continueelse:while True:userid = input("请输入身份证号:")if userid not in self.useridlist:print("身份证号不存在,请重新输入!")continueelse:if self.namelist.index(name) != self.useridlist.index(userid):print("姓名和身份证号不匹配,补卡失败!")else:idx = self.useridlist.index(userid)if self.cardlist[idx].islock:print("您的卡号已锁,请先解卡!")breakelse:self.cardlist[idx].cardid = str(100000 + len(self.personlist))cardid = 100000 + len(self.personlist)while str(cardid) in self.cardidlist:cardid += 1self.cardidlist[idx] = str(cardid)self.cardlist[idx].cardid = str(cardid)print(f"补卡成功!新卡号为:{self.cardidlist[idx]}")self.store()flag = 0breakdef change_pwd(self):idx = self.login()flag = 1while flag:password = input("请输入新密码(6位数字):")if len(password) == 6:for i in range(6):if password[i] not in self.data_list:print("新密码必须全部为数字,请重新输入新密码!")breakif i == 5:self.cardlist[idx].password = passwordprint("密码修改成功!")flag = 0self.store()breakelse:print("新密码必须为六位,请重新输入新密码!")def store(self):with open('./databases/userid.txt', 'ab') as fp:pickle.dump(self.personlist, fp)with open('./databases/cardid.txt', 'ab') as fp:pickle.dump(self.cardlist, fp)def __getusername(self):while True:name = input("请输入用户名:")# 检查用户名首字母不能为数字if name[0] in self.data_list:print("首字母不能为数字,请重新输入用户名!")continueelse:# 检查用户名是否已存在if name not in self.namelist:return nameelse:print("用户名已存在,请重新输入用户名!")def __getuserid(self):while True:userid = input("请输入身份证号(8位数字):")if len(userid) == 8:for i in range(8):if userid[i] not in self.data_list:print("身份证号必须全部为数字,请重新输入身份证号!")breakif i == 7:# 检查身份证号是否已存在if userid not in self.useridlist:return useridelse:print("身份证号已存在,请重新输入身份证号!")else:print("身份证号必须为八位,请重新输入身份证号!")def __getphoneNumber(self):while True:phoneNumber = input("请输入电话号码(6位数字):")if len(phoneNumber) == 6:for i in range(6):if phoneNumber[i] not in self.data_list:print("电话号码必须全部为数字,请重新输入电话号码!")breakif i == 5:return phoneNumberelse:print("电话号码必须为六位,请重新输入电话号码!")def __getpassword(self):while True:password = input("请输入密码(6位数字):")if len(password) == 6:for i in range(6):if password[i] not in self.data_list:print("密码必须全部为数字,请重新输入密码!")breakif i == 5:return passwordelse:print("密码必须为六位,请重新输入密码!")def input_pwd(self,cardid):idx = self.cardidlist.index(cardid)pwd = input("请输入密码,您共有3次机会:")num = 2while num:if pwd == self.cardlist[idx].password:return Trueelse:num -= 1pwd = input(f"密码错误,您还有{num + 1}次机会:")print("密码错误,已锁卡,请解卡!")self.lock(idx)return Falsedef login(self): # 如果返回数字,则登录成功,如果返回字符'a',则登录失败while True:cardid = input("请输入卡号:")if cardid in self.cardidlist: # 检查身份证号是否存在idx = self.cardidlist.index(cardid)if not self.cardlist[idx].islock: # 检查卡号是否锁住啦if self.input_pwd(cardid):return idxelse:return 'a'else:print("您的卡号已锁,请解卡!")return 'a'else:print("卡号未注册,请重新输入!")
personclass.py
class Person:def __init__(self,name,userid,phonenumber,cardid):self.name = name # 用户姓名self.userid = userid # 用户身份证号self.phoneNumber = phonenumber # 用户电话号self.cardid = cardid # 卡号
viewclass.py
import timeclass Views:def __init__(self):self.__show_welcome()print("系统正在启动中,请稍后...")time.sleep(1)self.show_operator()def __show_welcome(self):varstr = '''*******************************************************
* *
* *
* Welcome to Bank *
* *
* *
*******************************************************'''print(varstr)def show_operator(self):varstr_operator = '''*******************************************************
* (1)注册 (2)查询 *
* (3)取款 (4)存款 *
* (5)转账 (6)锁卡 *
* (7)解卡 (8)补卡 *
* (9)改密 (0)退出 *
*******************************************************'''print(varstr_operator)if __name__ == '__main__':obj = Views()
Python ATM实战相关推荐
- python项目实战——银行取款机系统(七)
项目实战目录 python项目实战--银行取款机系统(一) python项目实战--银行取款机系统(二) python项目实战--银行取款机系统(三) python项目实战--银行取款机系统(四) p ...
- python项目实战——银行取款机系统(一)
项目实战目录 python项目实战--银行取款机系统(一) 前言 今天我们将通过python完成简易银行提款机系统的实战,我们一步步实现我们的要求.话不多说,看操作. 环境使用 python 3.9 ...
- python项目实战——银行取款机系统(六)
项目实战目录 python项目实战--银行取款机系统(一) python项目实战--银行取款机系统(二) python项目实战--银行取款机系统(三) python项目实战--银行取款机系统(四) p ...
- 重磅升级,52个Python+OpenCV实战项目教你掌握图像处理
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 近期小白学视觉公众号推出了多篇Python+OpenCV实战项目的 ...
- 线程,协程对比和Python爬虫实战说明
此文首发于我的个人博客:线程,协程对比和Python爬虫实战说明 - zhang0peter的个人博客 这篇文章写的是我对线程和协程的理解,有错误之处欢迎指出. 举一个餐馆的例子.我们把一个餐厅当做一 ...
- 阿里P8连肝一周整理出这份python自动化测试实战PDF
由于细节内容实在太多啦,也为了不影响各位大大观看,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!总共整理了有282页的PDF文档,有需要的可以查看我文章最后. 整理了一份pyt ...
- python爬虫图片实例-【图文详解】python爬虫实战——5分钟做个图片自动下载器...
我想要(下)的,我现在就要 python爬虫实战--图片自动下载器 之前介绍了那么多基本知识[Python爬虫]入门知识(没看的赶紧去看)大家也估计手痒了.想要实际做个小东西来看看,毕竟: talk ...
- python自动化测试看什么书-《Python自动化测试实战》终于出版!!!
一.为什么会写这本书 1.系统梳理.可以加深对测试知识体系的系统梳理 2.名气.增加个人的名气,比如:面试时,可以很自豪的说,我是xxxx书的作者 3.利他.帮助有需要的学习者更系统.完备的学习和进阶 ...
- python入门新手项目-Python入门实战项目有哪些适合新手?
Python入门实战项目有哪些适合新手?目前市面上有很多适合新手的Python入门练手项目,Python入门需要理论与实践相结合,前面夯实基础知识,后面通过实战项目帮助你更好的运用这些Python知识 ...
最新文章
- 越南一难倒博士的趣味数学题
- 什么是C中的“静态”功能?
- AMDF换成ACF和AMDF合作算法
- Kaggle知识点:时序数据与Embedding
- 【数据结构与算法】之深入解析“最接近的三数之和”的求解思路与算法示例
- java 获得响应内容_Java 纯HTTP Get请求获取响应内容,如果302,继而获取重定向后的响应内容。...
- VIm中Python自动补全插件Pydiction
- java.lang.UnsatisfiedLinkError: Couldn't load XXX
- 合作共赢,共同飞跃 | DDG一站式数字化转型集成解决方案正式发布
- CHARACTERISTIC DEFINITION
- 用python做时间序列预测八:Granger causality test(格兰杰因果检验)
- 静态变量和静态方法编程训练—信用卡消费记录
- window用户切换
- 计算机课学生段密码,启课程学生端电脑版
- Matlab2013a学习之男女的声音识别
- 织梦文章发布 html仅动态,织梦dedecms采集文章后导出为仅动态的解决方案
- 天融信 还有什么型号服务器,天融信日志服务器
- 位图与bitblt【位图知识】
- AC_AttitudeControl_Heli.cpp的AC_AttitudeControl_Heli::rate_target_to_motor_yaw函数代码分析
- xlwings出现的报错