洗礼灵魂,修炼python(77)--全栈项目实战篇(5)—— ATM自动存取机系统
要求:
1.完成常识中的ATM存取款机功能
2.把ATM机故障考虑进去
3.不能直接输入账户名和卡号等等信息,模拟出插银行卡让ATM机自动读取卡信息
4.密码验证超过三次错误即锁定账户
5.操作类型有:存款,取款,查询,转账,打印凭条,退卡,一共六个选项,跟用户输入做出不同的反馈
6.当用户正常进入,列出操作类型,每次操作结束后都要重新选择操作类型,只有退卡操作才会结束
7.操作结束后,数据要同步更新
8.要有日志文件,每个涉及到钱走向的操作都要有日志记录
分析:
同样的没什么可说的,根据生活中的场景来就行
关键的问题:怎么模拟插卡操作,让ATM机自动获取信息,方法有:
1.调用API接口读取卡信息,但基本实现起来很难,除非真的搞来一个和现实中的ATM机一样的读卡设备
2.我想了很久,用一个文本文档,里面存放有卡号,用户名等基本信息,然后导入文本的数据来模拟插卡操作,剩下的操作就简单了
我希望你已经思考过再看的下面:
源代码及相关文件源码下载地址:传送门
需要四个文件:
主程序ATM.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #!usr/bin/env python #-*- coding:utf-8 -*- # author:yangva # datetime:2017/12/16 0015 13:32 import random,time atm_fault = random.randint( 0 , 100 ) #ATM机随机故障系数 if atm_fault = = 0 : print ( 'ATM出现故障,暂时不可用,抱歉给您带来不便' ) else : print ( 'ATM播放幻灯片,推销新业务(信用卡办理,VIP会员特权,新卡新功能等等)' ) #插入卡操作 try : #模拟读卡的操作,这里用文本文档代替 card = open ( input ( '欢迎光临,请在下方插入口插入您的银行卡(输入文本文件路径和文件名):' )) print ( '正在读卡,请稍后。。。' ) time.sleep( 2 ) f = eval (card.read()) username = list (f.keys())[ 0 ] #取出账户名 user_id = f[username][ 'ID' ] #取出银行卡号 except (NameError,IOError,FileNotFoundError): #输入的文本不存在则捕获 print ( '插入卡操作过程有误,请检查是否存在该文件或打开该文件的权限' ) else : f = open ( 'database.txt' , 'r' ) database = eval (f.read()) f.close() #这里不用with 语句,为保证数据库文件能立即关闭 print ( '%s先生,欢迎您!!!' % username[ 0 ]) #问候语 if username not in database.keys(): print ( '您的账户已冻结,请本人携带身份证到银行柜台解冻\n已退卡,请收好您的银行卡' ) else : password = input ( '请输入您的密码(密码为6位数字),请注意周围环境以及遮挡键盘操作:' ).strip() #后期可以改为语言提示 count = 0 #用于操作计数 ctrl_flag = False #标志位,用于跳出多层循环 while not ctrl_flag: if count = = 2 : print ( '您已输入多次错误密码,银行账户已冻结' ) with open ( 'log.txt' , 'a' ) as f2: #写入日志 database[ 'freeze' + username] = database.pop(username) f1 = open ( 'database.txt' , 'w' ) #同样的,不用with语句,保证数据文件立即关闭 f1.write( str (database)) f2.write( str (time.strftime( "%Y %b %d %X" )) + '\n用户 %s 的银行卡已冻结\n' % user_id) f1.close() ctrl_flag = True break if len ( str (password)) = = 6 : #用于判断输入的密码位数是否正确 if password = = database[username][ 'password' ]: database_bk = database #做临时备份数据的操作,方便后面出错时会滚 temp = '' #凭条 while not ctrl_flag: cont = input ( '1.取款\n2.存款\n3.转账\n4.查询\n5.打印凭条\n6.退卡\n请选择交易类型(输入对应的序号即可):' ) #账户主体操作 if cont = = '1' : #取款 withdraw_money = int ( input ( '请输入取款金额(最低一百):' )) #ATM存取都是100的整数,直接用int类型 if withdraw_money % 100 = = 0 : print ( '正在点钞,请稍后。。。' ) if withdraw_money > database[username][ 'balance' ]: print ( '操作失败,您输入的金额大于您的余额总数' ) else : time.sleep( 3 ) print ( '已成功出钞,请取走您的钞票 %s元' % withdraw_money) database[username][ 'balance' ] - = withdraw_money with open ( 'log.txt' , 'a' ) as f: #写入日志 f.write( str (time.strftime( "%Y %b %d %X" )) + '\t卡号为 %s 的用户 %s 取出金额:%d\n' % (user_id,username,withdraw_money)) temp + = str (time.strftime( "%Y %b %d %X" )) + '\t取款金额:%d\n' % withdraw_money #记录凭条 else : print ( '输入金额不是100的整数倍,请重新输入' ) elif cont = = '2' : #存款 save_money = int ( input ( '请将钞票叠好,并整齐放入存钞口(输入存款金额):' )) #ATM存取款都是100的整数,直接用int类型 print ( '正在点钞,请稍后。。。' ) time.sleep( 3 ) print ( '%s 元已成功存入账户 %s\t账户名 %s' % (save_money,user_id,username)) database[username][ 'balance' ] + = save_money with open ( 'log.txt' , 'a' ) as f: #写入日志 f.write( str (time.strftime( "%Y %b %d %X" )) + '\t卡号为 %s 的用户 %s 已存入金额 %d\n' % (user_id,username,save_money)) temp + = str (time.strftime( "%Y %b %d %X" )) + '\t存入金额:%d\n' % save_money elif cont = = '3' : #转账 transfer_id = input ( '请输入转账帐户卡号:' ) transfer_user = input ( '请输入帐户名:' ) if transfer_id = = database[transfer_user][ 'ID' ]: transfer_money = float ( input ( '请输入转账金额:' )) print ( '正在转账,请稍后。。。' ) time.sleep( 3 ) database[username][ 'balance' ] - = transfer_money database[transfer_user][ 'balance' ] + = transfer_money with open ( 'log.txt' , 'a' ) as f: #写入日志 f.write( str (time.strftime( "%Y %b %d %X" )) + '\t卡号为 %s 的用户 %s 转出金额为 %d 给卡号为 %s 的用户 %s\n' % (user_id,username,transfer_money,transfer_id,transfer_user)) print ( '成功转账 %s 给卡号为 %s 的用户 %s' % (transfer_money,transfer_id,transfer_user)) temp + = time.strftime( "%Y %b %d %X" ) + '\t向卡号为 %s 的用户 %s 转账 %d \n' % (transfer_id,transfer_user,transfer_money) else : print ( '输入的卡号为 %s 的用户名为 %s 账户有误,原因可能账户信息不匹配或被冻结' % (transfer_id,transfer_user)) elif cont = = '4' : #查询 print ( '您的余额为:%.2f' % database[username][ 'balance' ]) elif cont = = '5' : #打印凭条 print (temp) elif cont = = '6' : #退卡 print ( '正在退卡。。' ) time.sleep( 1 ) print ( '请取走您的银行卡,感谢使用' ) ctrl_flag = True break else : print ( '序号输入有误,可能不存在序号%s 对应的选项' % cont) else : count + = 1 password = input ( '输入有误,您还有 %s 次机会\n请重新输入:' % ( 3 - count)).strip() else : count + = 1 password = input ( '密码仅为6位数字,您还有 %s 次机会\n请重新输入: ' % ( 3 - count)).strip() with open ( 'log.txt' , 'a' ) as f1: #写入日志 f2 = open ( 'database.txt' , 'w' ) f2.write( str (database)) f1.write( str (time.strftime( "%Y %b %d %X" )) + '\t修改数据库文件\n' ) f2.close() |
日志文件log.txt(自动生成,初始状态为空)
模拟的银行卡文件card.txt
1 | { 'yang' :{ 'password' : '111111' , 'ID' : '6662008891880688689' }} |
数据文件database.txt
1 | { 'ling' : { 'password' : '123456' , 'ID' : '6662008891880688688' , 'balance' : 500.86 }, 'liu' : { 'password' : '888888' , 'ID' : '6662008891880688687' , 'balance' : 200000.0 }, 'tian' : { 'password' : '00000' , 'ID' : '6662008891880688680' , 'balance' : 448.03 }, 'liang' : { 'password' : '666666' , 'ID' : '6662008891880688681' , 'balance' : 522.5 }, 'yang' : { 'password' : '111111' , 'ID' : '6662008891880688689' , 'balance' : 21310.0 }} |
结果测试:
运行环境随便你了
(截图只展示了部分,全部效果自己去体验吧)
总结优化:
1.其实不光是这个ATM机,前面的几个项目里都可以用函数或者类来实现功能,如果你们感兴趣可以用函数或者类来操作。(为什么不用函数的原因后期有空再说)。其实我现在都还正在优化中,尽量的简化代码但功能又只增不减那种
2.相信聪明的你已经发现了,程序还没有加入取款当天内只能取多少,存款存多少(单次最多存取多少)的限制,这个就自己去优化了
3.可以优化和扩展的功能还有很多,你可以做成图形化界面,也可以编译成exe可执行文件,尽量的做到和真实的ATM机一样的功能,那你就牛逼了
分类:
洗礼灵魂,修炼python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】