阅读目录
一 项目介绍
ATM + 购物商城程序其实是通过模拟银行ATM机功能以及电商平台<购物商城程序>功能的实现,将前面大部分所学的知识点串联起来,让你们更好的去巩固python基础。这也是在学习python这门语言的第一个程序。
# 项目需求如下: ''' - 额度 15000或自定义 - 实现购物商城,买东西加入 购物车,调用信用卡接口结账 - 可以提现,手续费5% - 支持多账户登录 - 支持账户间转账 - 记录每月日常消费流水 - 提供还款接口 - ATM记录操作日志 - 提供管理接口,包括添加账户、用户额度,冻结账户等... - 用户认证功能 '''
二 一个项目是如何从无到有的?
在互联网企业里,所有项目一开始都是没有的,那项目是怎么来的呢?其实是通过客户的需求,从而诞生出一些列的软件。那也就是说我们无论开发什么项目,都是为了服务于人类,其实这也是计算机的使命,我们需要让机器替代人力去干活!所以企业中一个项目到底是如何从无到有的:
# 1、需求分析: ''' 开发项目前,都必须找到相应的客户,让客户给企业提出项目的需求,以及需要实现的功能有哪些,拿到需求后再提取出一些列功能。 ''' # 2、设计程序以及程序的架构 ''' 在所有一线开发的企业里,在一个项目开发前,都应该设计程序,那样会让程序解开耦合,从而提高项目的管理以及开发的效率。 ''' # 3、分任务开发 ''' 在公司里面,开发项目需要这几种岗位人才: UI设计: 软件的外观设计者,通过一些炫酷的设计,提高用户的对软件的体验感。 前端开发: UI设计仅仅只是把一些外观图设计出来,那前端开发需要把UI的设计图拿到之后,对软件界面的进行排版。 后端开发(python): 项目里业务以及功能的逻辑处理! ''' # 4、项目测试 ''' 测试工程师: 对后端以及前端开发好的项目进行功能和性能测试,测试的过程中出现bug就会立即让开发人员去修整,待整个项目几乎没有bug,以及性能达到项目实际的预期,就会准备上线运行。 测试分为两种: 1.黑盒测试: 通过对软件界面的功能进行测试,测试一些能让用户看到的bug。(例如穿越火线的卡箱子等等...) 2.白盒测试: 对软件进行性能测试,例如每秒钟能承受多少用户量的访问等... ''' # 5、上线运行 ''' 运维工程师(linux): 拿到前面整个项目编写完的代码,部署到服务器,上线运行! '''
三 需求分析
需求分析就是把客户的一些项目需求,提取出一个个相应的功能。
# 提取功能 ''' - 额度 15000或自定义 -----> 注册功能 - 实现购物商城,买东西加入购物车,调用信用卡接口结账 -----> 购物、支付 - 可以提现,手续费5% -----> 提现 - 支持多账户登录 -----> 登陆 - 支持账户间转账 -----> 转账 - 记录每月日常消费流水 -----> 记录流水 - 提供还款接口 -----> 还款 - ATM记录操作日志 -----> 记录日志 - 提供管理接口,包括添加账户、用户额度,冻结账户等... -----> 管理员功能:添加用户,冻结账户 - 用户认证功能 -----> 用户认证装饰器 ''' # 提取完后能后我们应该再分析出展示给用户的功能: ''' 1 登入 2 注册 3 查看余额 4 转账 5 还款 6 取款 7 查看流水 8 购物 9 查看商品 10 管理用户 '''
四 设计程序以及程序架构
在写程序之前不是一拿到项目需求想到哪就写到哪。假设你的程序有成千上万个功能,你都把他们写在一个文件里面。还有用户输入、逻辑处理、数据存储都写在一个函数里,会导致你的代码结构及其不清晰。而是应该对程序进行设计,设计出一种最优的程序架构!
这样做会有什么好处:
1.思路清晰
2.不会出现写到一半的时候推翻重写
3.方便自己或以后同事的维护
那么接下来我们开始设计我们的程序架构,把一个程序架构分为三层:
这个架构为何要这样设计呢?有何好处:
1 把每个功能都分成三个部分,逻辑清楚
2 如果要改用户的数据展示,或者换存储机制,只需动单独一个模块就可以了,扩展性强
3 为什么把日志模块放在接口层,因为所有的交互都会经过接口层,方便记录
五 程序目录设计
程序目录的设计应该对应着上面的架构图创建相应文件夹, 文件名可以随便取,但是最好要让别人看到就知道是干嘛用的。
# 接下来我们写的功能都在按照这个文件目录来写,请认真阅读这个目录所对应的功能。 ''' - ATM - conf 配置文件文件夹 - setting.py - lib 公共方法文件夹 - common.py 公共方法文件 - interface 接口层文件夹 - user.py 用户接口文件 - shop.py 购物接口文件 - bank.py 银行接口文件 - core 用户功能文件夹 - src.py 视图文件 - db 数据处理层文件夹 - db_handler.py 数据处理功能文件 - log 日志存放目录 - start.py 程序的入口文件,启动文件 - readme 程序的说明文件 '''
六 项目详解
1、程序入口
从入口文件开始写在start.py,这里是我们程序的入口,我们要运行程序,从这里开始,通过这里到到达用户功能层。
import os, sys # 找到当前项目所在位置 path = os.path.dirname(__file__) # 项目目录加入到环境变量中 sys.path.append(path) # 导入用户功能层中的src.py文件 from core import src if __name__=="__main__": # 执行src中的run方法启动程序 src.run()
2、注册
1.从start.py进入到在core的src.py(用户功能层)中,我们再run方法中列出我们所有的功能,编号与func_dic字典中键对应,值是函数地址,用户输入以后调用register方法。
2.在register方法中接收用户输入的用户名,密码,重复密码,如果两次密码不一致,则从新输入,如果一致则调用lib文件中user.register_interface(name,password)方法(接口层),等待接口层返回,如果返回True这注册成功,如果返回False则展示错误信息,重新注册。
3.在user.register_interface(name,password)调用db文件夹中的db_handler.select(name)(数据处理层),接收数据,如果有该用户的信息怎么返回False,'用户已存在'给用户功能层的register方法。如果不存在则db文件夹中的db_handler.save(dic)(数据处理层)方法,保存用户信息。并返回True,'注册成功'。
4.db文件夹中的db_handler.save(dic)(数据处理层),将以用户的用户名为文件名,将用户信息转化为json数据存储。db文件夹中的db_handler.select(name)(数据处理层)返回用户信息已字典的形式。
用户功能层:
from interface import user ''' 在register方法中接收用户输入的用户名,密码,重复密码,如果两次密码不一致,则从新输入,如果一致则调用lib文件中user.register_interface(name,password)方法(接口层),等待接口层返回,如果返回True这注册成功,如果返回False则展示错误信息,重新注册 ''' #实现注册函数 def register(): print('用户注册') while True: name = input("请输入你的姓名:").strip() password = input("请输入你的密码:").strip() re_password =input("请确认密码:").strip() #判单两次密码一致 if password == re_password: #调用接口层中interface文件中的user.py中的注册接口,传入用户名,和密码 flag,msg=user.register_interface(name,password) #接口返回的数据进行判断,如果返回True if flag: # 展示返回的信息 print(msg) # 结束功能 break # 如果返回的是False else: print(msg) else: print('两次密码不一致')
接口层:
# 导入数据处理层db中的db_handler.py from db import db_handler ''' 在user.register_interface(name,password)调用db文件夹中的db_handler.select(name)(数据处理层),接收数据,如果有该用户的信息怎么返回False,'用户已存在'给用户功能层的register方法。如果不存在则db文件夹中的db_handler.save(dic)(数据处理层)方法,保存用户信息。并返回True,'注册成功' ''' def register_interface(name,password,balance=1500): #通过db_handler中的select方法查看用户名是否存在 user=db_handler.select(name) #如果用户名存在 if user: return False,"用户名已存在" else: #将用户数据组成字典,为了后续功能现在把用户信息都存起来 user_dic={ 'name':name,#用户名 'password':password,#密码 'lock':False,#是否锁定 'balance':balance,#余额 'bankflow':[],#流水记录 'shoppingcart':{}#购物车商品 } #传到db_handler中的save方法保存 db_handler.save(user_dic) return True,"注册成功"
数据处理层:
# 我们将用户名作为文件名,用户信息文件放在db文件夹中 import os # 导入配置文件 from conf import setting import json ''' db文件夹中的db_handler.select(name)(数据处理层)返回用户信息已字典的形式 ''' # 从文件中查找用户信息 def select(name): # setting.base_db表示db文件夹的路径,path表示用户的文件的路径 path = os.path.join(setting.base_db, "%s.json" % name) # 判断有没有以用户命名的文件,如果有,读出数据并返回 if os.path.exists(path): with open(path, 'r', encoding="utf-8") as f: return json.load(f) # 如果有,返回False else: return False ''' db文件夹中的db_handler.save(dic)(数据处理层),将以用户的用户名为文件名,将用户信息转化为json数据存储。 ''' # 将传过来的字段存到db文件夹下的已用名为文件名的.json文件中 def save(user_dic): # 找到文件路径 path = os.path.join(setting.base_db, "%s.json" % user_dic['name']) # 写入文件 with open(path, 'w', encoding='utf-8') as f: json.dump(user_dic, f) f.flush()
配置文件:
import os '''提供项目目录和bd文件夹目录''' base_path=os.path.dirname(os.path.dirname(__file__)) base_db=os.path.join(base_path,'db')
通过上面的注册功能我们把数据层的功能已经完成,后续所有功能都不需要动,而且程序基本架构已经完成,后续执行在这个基础上增加功能代码就可以了。
3、登陆
1.在src.py(用户功能层)的run方法中添加“ 登入” 在func_dic添加login,然后实现login,就可以了,我们把上面的run方法写好以后,要添加新的功能是不是特别简单。 2.我们在src.py(用户功能层)中实现login方法,在login函数中接收用户输入的用户名和密码后,后调用interface中的user.login_interface(name,password)(接口层),等待接口层返回,如果返回True这将用户名存到user_dic={'name':None}中,作为保存登入状态,如果返回False则登入失败,显示失败原因。 3.在interface文件夹中的user.login_interface(name,password)(接口层)方法中,调用db文件夹中的db_handler.select(name)(数据处理层)方法,如果数据不存在则返回False,"用户不存在",如果有数据则判断取出的数据是否和用户输入的密码是否一致且用户没有被锁定。如果一致且没有没有被锁定,则返回True,"登入成功",反之返回False,"密码错误或用户被锁定"。
用户功能层:
''' 我们在src.py(用户功能层)中实现login方法,在login函数中接收用户输入的用户名和密码后,后调用interface中的user.login_interface(name,password)(接口层),等待接口层返回,如果返回True这将用户名存到user_dic={'name':None}中,作为保存登入状态,如果返回False则登入失败,显示失败原因。 ''' def login(): if user_dic['name']: print('你已登入,不能注册') return print("登入") while True: name = input('请输入用户名').strip() password = input('请输入密码').strip() flag, msg = user.login_interface(name, password) if flag: user_dic['name'] = name print(msg) break else: print(msg) ''' 在src.py(用户功能层)的run方法中添加“ 登入” 在func_dic添加login,然后实现login,就可以了,我们把上面的run方法写好以后,要添加新的功能是不是特别简单。 ''' func_dic = { '1': register, '2': login } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') print(choice) # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic:continue print(func_dic[choice]) func_dic[choice]()
接口层:
# 导入数据处理层db中的db_handler.py from db import db_handler ''' 在interface文件夹中的user.login_interface(name,password)(接口层)方法中,调用db文件夹中的db_handler.select(name)(数据处理层)方法,如果数据不存在则返回False,"用户不存在",如果有数据则判断取出的数据是否和用户输入的密码是否一致且用户没有被锁定。如果一致且没有没有被锁定,则返回True,"登入成功",反之返回False,"密码错误或用户被锁定" ''' # 登入接口 def login_interface(name, password): # 查找name的用户数据 user_dic = db_handler.select(name) # 如果有 if user_dic: # 如果密码正确切用户没有被锁定 if password == user_dic['password'] and not user_dic['lock']: return True, "登入成功" else: return False, '密码错误或者已经锁定' else: return False, "用户已存在"
4、用户认证
后续的功能我们要保证用户只有在登入的状态下才能使用,如果用户没有登入就让用户登入。那我们如何保证只有登入才能使用,不然跳转到登入,我们用装饰器实现
公共方法:
def auth_login(func): from core import src def wrapper(*args,**kwargs): if src.user_dic['name']: return func(*args,**kwargs) else: src.login() return wrapper
5、查看余额
1.在src.py(用户功能层)的run方法中添加“ 查看流水” 在func_dic添加check_balance,然后实现check_balance就可以了。
2.在check_balance方法上加登入认证装饰器,保证用户是登入状态。
3.在src.py(用户功能层)check_balance方法中调用interface文件夹下的bank.check_balance_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),获取用户的余额,并打印。
4.在interface文件夹下的bank文件中check_balance_interface方法调用db文件夹下的db_handle文件中的selec方法,获取用户的信息,并返回用户的余额。
用户功能层:
# **具体代码 ** # 对于查看余额功能在只需要src.py文件中func_dic添加check_balance,并实现check_balance函数 from interface import user, bank from lib import common # 记录登入信息的字典,初始值为None user_dic = {'name': None} ''' 1 在check_balance方法上加登入认证装饰器,保证用户是登入状态 2 在src.py(用户功能层)check_balance方法中调用interface文件夹下的bank.check_balance_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),获取用户的余额,并打印 ''' @common.auth_login def check_balance(): print("查看余额") # 调用bank的查询余额接口 balance = bank.check_balance_interface(user_dic['name']) print(balance) ''' 在src.py(用户功能层)的run方法中添加“ 查看流水” 在func_dic添加check_balance,然后实现check_balance,就可以了 ''' func_dic = { '1': register, '2': login, '3': check_balance, } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
''' 在interface文件夹下的bank文件中check_balance_interface方法调用db文件夹下的db_handle文件中的selec方法,获取用户的信息,并返回用户的余额 ''' #导入数据操作文件 from db import db_handler #查看用户的余额接口 def check_balance_interface(name): #调用数据查找方法 user_dic=db_handler.select(name) return user_dic['balance']
6、转账功能
1.在src.py(用户功能层)的run方法中添加“ 转账” 在func_dic添加transfer,然后实现transfer就可以了。 2.在transfer方法上加登入认证装饰器,保证用户是登入状态。 3.接收用户输入的要转账的用户名以及金额,并保证用户输入的金额为数字。 4.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.transfer_interface(user_dic['name'],to_user,account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则转账成功。 5.在interface文件夹下的bank文件中transfer_interface(from_name,to_name,account)方法调用db文件夹下的db_handle文件中的selec方法,获取to_name用户的信息,如果没有则返回False,"要转账的用户不存在",如果存在,则调用db文件夹下的db_handle文件中的selec方法,获取from_name用户的信息,判断要转账的金额是不是大于当前会员的余额,如果大于则返回False,"余额不足",如果余额充足,将扣减当前用户的余额,增加to_name用户的余额,并将流水记入到两个用户的信息中,然后做用户信息的保存,并返回True,"转账成功"。
用户功能层:
# 对于转账功能在只需要src.py文件中func_dic添加transfer,并实现transfer函数 from interface import user, bank from lib import common ''' 1 在transfer方法上加登入认证装饰器,保证用户是登入状态 2 接收用户输入的要转账的用户名以及金额,并保证用户输入的金额为数字, 3 在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.transfer_interface(user_dic['name'],to_user,account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则转账成功 ''' @common.auth_login def transfer(): print('转账') while True: to_user = input('请输入对方的账户:').strip() account = input("请输入转账的金额:").strip() # 判断是不是纯数字的字符串 if account.isdigit(): # 将数字字符串转化为数字 account = int(account) # 调用bank的转账接口,用户,转账用户,金额 flag, msg = bank.transfer_interface(user_dic['name'], to_user, account) if flag: print(msg) break else: print(msg) else: print("请输入数字") ''' 在src.py(用户功能层)的run方法中添加“ 转账” 在func_dic添加transfer,然后实现transfer,就可以了 ''' func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
#导入数据操作文件 from db import db_handler #查看用户的余额接口 def check_balance_interface(name): #调用数据查找方法 user_dic=db_handler.select(name) return user_dic['balance'] ''' 在interface文件夹下的bank文件中transfer_interface(from_name,to_name,account)方法调用db文件夹下的db_handle文件中的selec方法,获取to_name用户的信息,如果没有则返回False,"要转账的用户不存在",如果存在 则调用db文件夹下的db_handle文件中的selec方法,获取from_name用户的信息,判断要转账的金额是不是大于当前会员的余额,如果大于则返回False,"余额不足",如果余额充足,将扣减当前用户的余额,增加to_name用户的余额,并将流水记入到两个用户的信息中,然后做用户信息的保存,并返回True,"转账成功" ''' #转账接口 def transfer_interface(from_name,to_name,account): #查看被转账户信息 to_user_dic = db_handler.select(to_name) #如果被转账户存在 if to_user_dic: #查找当前用户的信息 from_user_dic = db_handler.select(from_name) #如果当前用户余额大于等于要转金额 if from_user_dic['balance']>= account: #对当前用户余额做扣减 from_user_dic['balance']-=account #对被转账用户余额做增加 to_user_dic['balance']+=account #将转账记录到当前用户的流水中 from_user_dic['bankflow'].append('%s向%s转账%s'%(from_name,to_name,account)) #将转账记录到被转账用户的流水中 to_user_dic['bankflow'].append('%s收到%s转账%s'%(to_name,from_name,account)) db_handler.save(from_user_dic) db_handler.save(to_user_dic) return True,"转账成功" else: return False,"您的额度不够" #如果被转账户不存在 else: return False,"对方账号不存在"
7、还款功能
1.在src.py(用户功能层)的run方法中添加“转账”在func_dic添加repay,然后实现repay就可以了。
2.在repay方法上加登入认证装饰器,保证用户是登入状态
3.接收用户输入的要还款的金额,并保证用户输入的金额为数字,
4.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.bank.repay_interface(user_dic['name'],account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则还款成功。
5.在interface文件夹下的bank文件中repay_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的信息,增加user_dic['name']用户的余额,并将流水记入到该用户的信息中,然后做用户信息的保存,并返回True,"还款成功"。
用户功能层:
from interface import user, bank from lib import common # 记录登入信息的字典,初始值为None user_dic = {'name': None} ''' 1 在repay方法上加登入认证装饰器,保证用户是登入状态 2 接收用户输入的要还款的金额,并保证用户输入的金额为数字, 3 在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.bank.repay_interface(user_dic['name'],account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则还款成功 ''' @common.auth_login def repay(): print("还款") while True: account = input("请输入还款金额").strip() if account.isdigit(): account = int(account) flag, msg = bank.repay_interface(user_dic['name'], account) if flag: print(msg) break else: print(msg) else: print("请输入数字") ''' 在src.py(用户功能层)的run方法中添加“ 转账” 在func_dic添加repay,然后实现repay,就可以了 ''' func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer, '5': repay, } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 5 还款 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer '5':repay } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
#导入数据操作文件 from db import db_handler ''' 在interface文件夹下的bank文件中repay_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的信息,增加user_dic['name']用户的余额,并将流水记入到该用户的信息中,然后做用户信息的保存,并返回True,"还款成功" ''' #还款接口 def repay_interface(name,account): #查找当前用户的信息 user_dic=db_handler.select(name) #增加用户的余额 user_dic['balance']+=account #增加还款信息记录到流水中 user_dic['bankflow'].append('还款%s'%(account)) #保存用户信息 db_handler.save(user_dic) return True,"还款成功"
8、取款功能
1.在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加withdraw,然后实现withdraw就可以了。
2.在withdraw方法上加登入认证装饰器,保证用户是登入状态。
3.接收用户输入的要取款的金额,并保证用户输入的金额为数字。
4.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.withdraw_interface(user_dic['name'],account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则取款成功。
5.在interface文件夹下的bank文件中withdraw_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的信息,查看user_dic['name']用户的余额,如果取款金额乘1.05后,大于用户余额,则返回False,'余额不足',若不大于余额,这扣减用户的余额,并将流水记入到该用户的信息中,然后做用户信息的保存,并返回True,"取款成功"。
用户功能层:
from interface import user, bank from lib import common # 记录登入信息的字典,初始值为None user_dic = {'name': None} ''' 1 在withdraw方法上加登入认证装饰器,保证用户是登入状态 2 接收用户输入的要取款的金额,并保证用户输入的金额为数字, 3 在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.withdraw_interface(user_dic['name'],account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则取款成功 ''' @common.auth_login def withdraw(): print('取款') while True: account = input('请输入取款金额').strip() if account.isdigit(): account = int(account) flag, msg = bank.withdraw_interface(user_dic['name'], account) if flag: print(msg) break else: print(msg) else: print('请输入数字') ''' 在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加withdraw,然后实现withdraw,就可以了 ''' func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer, '5': repay, '6': withdraw } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 5 还款 6 取款 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer, '5':repay, '6':withdraw } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
#导入数据操作文件 from db import db_handler ''' 在interface文件夹下的bank文件中withdraw_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的信息,查看user_dic['name']用户的余额,如果取款金额乘1.05后,大于用户余额,则返回False,'余额不足',若不大于余额,这扣减用户的余额,并将流水记入到该用户的信息中,然后做用户信息的保存,并返回True,"取款成功" ''' #取款接口 def withdraw_interface(name,account): user_dic = db_handler.select(name) account = account*1.05 if user_dic['balance']>=account: user_dic['balance']-=account user_dic['bankflow'].append('取款%s'%(account)) db_handler.save(user_dic) return True,"取款成功" else: return False,"余额不足"
9、查看流水
1.在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加check_records,然后实现check_records就可以了
2.在check_records方法上加登入认证装饰器,保证用户是登入状态。
3.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.check_records_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则取款成功。
4.在interface文件夹下的bank文件中check_records_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的流水信息并返回。
用户功能层:
from interface import user, bank from lib import common # 记录登入信息的字典,初始值为None user_dic = {'name': None} ''' 1 在check_records方法上加登入认证装饰器,保证用户是登入状态 2 在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.check_records_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则取款成功 ''' @common.auth_login def check_records(): print("查看流水") records = bank.check_records_interface(user_dic['name']) if records: for record in records: print(record) else: print("暂无流水") ''' 在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加check_records,然后实现check_records,就可以了 ''' func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer, '5': repay, '6': withdraw, '7': check_records, } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 5 还款 6 取款 7 查看流水 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer, '5':repay, '6':withdraw, '7':check_records } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
#导入数据操作文件 from db import db_handler ''' 在interface文件夹下的bank文件中check_records_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的流水信息并返回 ''' #查看流水接口 def check_records_interface(name): user_dic=db_handler.select(name) return user_dic['bankflow']
10、购物车功能
# 购物车需求 ''' 1 先循环打印出商品 2 用户输入数字选择商品(判断是否是数字,判断输入的数字是否在范围内) 3 取出商品名,商品价格 4 判断用户余额是否大于商品价格 5 余额大于商品价格时,判断此商品是否在购物车里 5.1 在购物车里,个数加1 5.1 不在购物车里,拼出字典放入({‘car’:{‘price’:1000,‘count’:2},‘iphone’:{‘price’:10,‘count’:1}}) 6 用户余额减掉商品价格 7 花费加上商品价格 8 当输入 q时,购买商品 8.1 消费为0 ,直接退出 8.2 打印购物车 8.3 接受用户输入,是否购买 当输入y,直接调购物接口实现购物 9 商品列表 goods_list = [ ['凤爪', 50], ['T-shirt', 150], ['macbook', 21800], ['iphoneX', 7000] ] '''
1.在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加shopping,然后实现shopping就可以了。
2.在shopping方法上加登入认证装饰器,保证用户是登入状态。
3.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.check_balance_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回的用户余额,打印商品列表,等待用户输入要购买的商品编号,将商品名称,价钱,数量加入到shoppingcart字典中,计算购车中所有商品所需的金额,如果大于用户余额,则添加失败,如果小与则添加成功,当用户输入q的时候结束购买,调用调用interface文件夹下的shop.shoping_interface(user_dic['name'],cost,shoppingcart)方法,(接口层,因为这里和购物相关我们把这个接口写在了shop文件中)等待返回结果并展示。
4.在interface文件夹下的shop文件中shoping_interface(name,cost,shoppingcart)调用在interface文件夹下的bank文件中的consume_interface(name,cost)(因为和钱相关我们写到bank文件中)方法,该方法中调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的流水信息对金额判断,如果余额充足,则扣减金额,记录日志,如果成功则返回True。在shoping_interface方法中将购物车的信息保存在用户的信息中,返回购买成功,如果consume_interface中发现金额不足则返回False,在shoping_interface方法将返回购买成功。
用户功能层:
from interface import user, bank,shop from lib import common # 记录登入信息的字典,初始值为None user_dic = {'name': None} ''' 在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.check_balance_interface(user_dic['name'])方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回的用户余额,打印商品列表,等待用户输入要购买的商品编号,将商品名称,价钱,数量加入到shoppingcart字典中,计算购车中所有商品所需的金额,如果大于用户余额,则添加失败,如果小与则添加成功,当用户输入q的时候结束购买,调用调用interface文件夹下的shop.shoping_interface(user_dic['name'],cost,shoppingcart)方法,(接口层,因为这里和购物相关我们把这个接口写在了shop文件中)等待返回结果并展示。 ''' @common.auth_login def shopping(): print("购物车") goods_list = [ ['coffee', 10], ['chicken', 20], ['car', 10000] ] user_balance = bank.check_balance_interface(user_dic['name']) cost = 0 shoppingcart = {} # {name:{'price':10,count:1}} while True: for i, goods in enumerate(goods_list): print("%s:%s" % (i, goods)) buy = input("请输入要购买的商品(数字)(q退出并购买):") if buy.isdigit(): buy = int(buy) if buy < len(goods_list): goods_name = goods_list[buy][0] goods_price = goods_list[buy][1] if user_balance >= goods_price: if goods_name not in shoppingcart: shoppingcart[goods_name] = {'price': goods_price, 'count': 1} else: shoppingcart[goods_name]['count'] += 1 user_balance -= goods_price cost += goods_price print("添加到购物车成功") else: print("余额不足") else: print("请选择存在的商品") elif buy == 'q': if shoppingcart: flag, msg = shop.shoping_interface(user_dic['name'], cost, shoppingcart) if flag: print(msg) break else: print(msg) break else: print('请输入数字') ''' 1 在src.py(用户功能层)的run方法中添加“ 取款” 在func_dic添加shopping,然后实现shopping,就可以了 2 在shopping方法上加登入认证装饰器,保证用户是登入状态 ''' func_dic = { '1': register, '2': login, '3': check_balance, '4': transfer, '5': repay, '6': withdraw, '7': check_records, '8': shopping, } # 打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 5 还款 6 取款 7 查看流水 8 购物车 ''') # 用户输入数字,执行各自的方法 choice = input('请选择:') # 我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer, '5':repay, '6':withdraw, '7':check_records, '8':shopping, } ''' # 如果用户输入的不在字典中则结束本次循环 if choice not in func_dic: continue func_dic[choice]()
接口层:
from db import db_handler from interface import bank ''' 在interface文件夹下的shop文件中shoping_interface(name,cost,shoppingcart)调用在interface文件夹下的bank文件中的consume_interface(name,cost)(因为和钱相关我们写到bank文件中)方法,该方法中调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的流水信息对金额判断,如果余额充足,则扣减金额,记录日志,如果成功则返回True。在shoping_interface方法中将购物车的信息保存在用户的信息中,返回购买成功,如果consume_interface中发现金额不足则返回False,在shoping_interface方法将返回购买成功, ''' def shoping_interface(name,cost,shoppingcart): flag=bank.consume_interface(name,cost) if flag: user_dic = db_handler.select(name) user_dic['shoppingcart']=shoppingcart db_handler.save(user_dic) return True,"购买成功" else: return False,"购买失败"
#导入数据操作文件 from db import db_handler ''' bank文件中的consume_interface(name,cost)(因为和钱相关我们写到bank文件中)方法,该方法中调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的流水信息对金额判断,如果余额充足,则扣减金额,记录日志,如果成功则返回True。在shoping_interface方法中将购物车的信息保存在用户的信息中,返回购买成功,如果consume_interface中发现金额不足则返回False ''' #消费接口 def consume_interface(name,account): user_dic=db_handler.select(name) if user_dic['balance']>=account: user_dic['balance']-=account user_dic['bankflow'].append('消费%s'%(account)) db_handler.save(user_dic) return True else: return False
11、查看购物车
1.在src.py(用户功能层)的run方法中添加“ 查看购物车” 在func_dic添加check_shoppingcard,然后实现check_shoppingcard,就可以了。
2.在check_shoppingcard方法上加登入认证装饰器,保证用户是登入状态。
3.在src.py(用户功能层)transfer方法中调用interface文件夹下的shop.check_shopingcart_interface(user_dic['name'])方法,(接口层,因为这里和购物相关我们把这个接口写在了shop文件中),等待接口返回数据,展示数据。
4.在interface文件夹下的shop文件中check_shopingcart_interface(user_dic['name'])方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的购物车信息并返回。
用户功能层:
from interface import user,bank from lib import common #记录登入信息的字典,初始值为None user_info={'name':None} ''' 在src.py(用户功能层)transfer方法中调用interface文件夹下的shop.check_shopingcart_interface(user_dic['name'])方法,(接口层,因为这里和购物相关我们把这个接口写在了shop文件中),等待接口返回数据,展示数据 ''' @common.login_auth def check_shoppingcard(): print("查看购物车") shoppingcard=shop.check_shopingcart_interface(user_dic['name']) print(shoppingcard) ''' 1 在src.py(用户功能层)的run方法中添加“ 查看购物车” 在func_dic添加check_shoppingcard,然后实现check_shoppingcard,就可以了 2 在check_shoppingcard方法上加登入认证装饰器,保证用户是登入状态 ''' func_dic={ '1':register, '2':login, '3':check_balance, '4':transfer, '5':repay, '6':withdraw, '7':check_records, '8':shopping, '9':check_shoppingcard, } #打印用户的功能模块 def run(): while True: print(''' 1 注册 2 登入 3 查看流水 4 转账 5 还款 6 取款 7 查看流水 8 购物车 9 查看购物车接口 '''') #用户输入数字,执行各自的方法 choice = input('请选择:') #我们知道函数可以做容器类型的元素,我们定义一个函数的字典 ''' func_dic = { '1':register, '2':login, '3':check_balance, '4':transfer, '5':repay, '6':withdraw, '7':check_records, '8':shopping, '9':check_shoppingcard, } ''' #如果用户输入的不在字典中则结束本次循环 if choice not in func_dic:continue func_dic[choice]()
接口层:
from db import db_handler from interface import bank ''' 在interface文件夹下的shop文件中check_shopingcart_interface(user_dic['name'])方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的购物车信息并返回 ''' #查看购车接口 def check_shopingcart_interface(name): user_dic=db_handler.select(name) return user_dic['shoppingcart']
12、日志功能
1.conf文件夹中的setting文件中配置日志。
2.在lib文件夹的common文件中生成日志对象。
3.在需要调用的地方,直接获取日志对象,生成日志。
4.后续要用直接传入名字,生成不同的名字即可。
设置文件目录:
""" logging配置 """ # 定义三种日志输出格式 开始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 logfile_dir = os.path.join(BASE_PATH, 'log') # log文件的目录 logfile_name = 'atm_shop_log.log' # log文件名 # 如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, 'handlers': { # 打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, # 打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { # logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, }
公共方法:
import logging.config from conf import setting ''' 在lib文件夹的common文件中生成日志对象 ''' #生成日志对象 def get_logger(name): logging.config.dictConfig(setting.LOGGING_DIC) my_logger=logging.getLogger(name) return my_logger
使用日志功能:
#导入数据操作文件 from db import db_handler #导入公共方法文件 from lib import common #生成bank日志对象 bank_logger=common.get_logger('bank') #查看用户的余额接口 def check_balance_interface(name): #调用数据查找方法 user_dic=db_handler.select(name) return user_dic['balance'] #转账接口 def transfer_interface(from_name,to_name,account): #查看被转账户信息 to_user_dic = db_handler.select(to_name) #如果被转账户存在 if to_user_dic: #查找当前用户的信息 from_user_dic = db_handler.select(from_name) #如果当前用户余额大于等于要转金额 if from_user_dic['balance']>= account: #对当前用户余额做扣减 from_user_dic['balance']-=account #对被转账用户余额做增加 to_user_dic['balance']+=account #将转账记录到当前用户的流水中 from_user_dic['bankflow'].append('%s向%s转账%s'%(from_name,to_name,account)) #将转账记录到被转账用户的流水中 to_user_dic['bankflow'].append('%s收到%s转账%s'%(to_name,from_name,account)) db_handler.save(from_user_dic) db_handler.save(to_user_dic) #调用日志 bank_logger.info('%s收到%s转账%s'%(to_name,from_name,account)) return True,"转账成功" else: return False,"您的额度不够" #如果被转账户不存在 else: return False,"对方账号不存在" #还款接口 def repay_interface(name,account): #查找当前用户的信息 user_dic=db_handler.select(name) #增加用户的余额 user_dic['balance']+=account #增加还款信息记录到流水中 user_dic['bankflow'].append('还款%s'%(account)) #保存用户信息 db_handler.save(user_dic) return True,"还款成功" #取款接口 def withdraw_interface(name,account): user_dic = db_handler.select(name) account = account*1.05 if user_dic['balance']>=account: user_dic['balance']-=account user_dic['bankflow'].append('取款%s'%(account)) db_handler.save(user_dic) return True,"取款成功" else: return False,"余额不足" #查看流水接口 def check_records_interface(name): user_dic=db_handler.select(name) return user_dic['bankflow'] #消费接口 def consume_interface(name,account): user_dic=db_handler.select(name) if user_dic['balance']>=account: user_dic['balance']-=account user_dic['bankflow'].append('消费%s'%(account)) db_handler.save(user_dic) return True else: return False
七 Github:
1.在src.py(用户功能层)的run方法中添加“ 转账” 在func_dic添加repay,然后实现repay,就可以了
2.在repay方法上加登入认证装饰器,保证用户是登入状态
3.接收用户输入的要还款的金额,并保证用户输入的金额为数字,
4.在src.py(用户功能层)transfer方法中调用interface文件夹下的bank.bank.repay_interface(user_dic['name'],account)方法,(接口层,因为这里和钱相关我们把这个接口写在了bank文件中),等待接口返回数据,如果返回False则失败并打印错误原因。如果返回True则还款成功
5.在interface文件夹下的bank文件中repay_interface(user_dic['name'],account)方法调用db文件夹下的db_handle文件中的selec方法,获取user_dic['name']用户的信息,增加user_dic['name']用户的余额,并将流水记入到该用户的信息中,然后做用户信息的保存,并返回True,"还款成功"