软件开发目录规范
bin 执行文件 start
core 核心文件 src 核心逻辑
conf 配置文件
lib 共享文件 common
log 日志文件
db 数据文件
interface 接口
shopping 购物车
import time,json
money = 0
car = {}
# 读取数据
def read_data(filename,lst = []):
with open(filename,mode="r+",encoding="utf-8") as fp:
for i in fp:
dic = json.loads(i)
lst.append(dic)
return lst
# 商品列表
goods_lst = read_data("shopping_data.json")
# 进度条
def progress(percent):
# 如果百分比超过了1,说明数据已经接收完毕
if percent > 1:
percent = 1
# 打印对应的进度条
strvar = "#" * int(50 * percent)
# %% => %
print("\r[%-50s] %d%%" % (strvar,int(100 * percent)),end="")
# 执行进度条
def exe_process():
# 初始化接收的字节数
recv_size = 0
# 文件总大小
total_size = 102400
while recv_size < total_size:
recv_size += 1024
# 模拟延迟
time.sleep(0.01)
# 计算百分比
percent = recv_size // total_size
# 调用进度条
progress(percent)
# 充值
def recharge():
global money
while True:
strvar = input("请充值吧,大哥~")
if strvar.isdecimal():
money = int(strvar)
print("恭喜您~ 充值成功{}元人民币".format(money))
break
else:
print("充值失败,非数字")
# 加载中
def loading():
print("加载商品中 ... ")
exe_process()
print()
# 展现商品
def show_goods():
# 序号 商品名称 价格
strvar = "{}".format("商品名称").center(20)
print("序号"+strvar+"价格")
for k,v in enumerate(goods_lst,start=1):
# 把序号加到字典v当中
v["num"] = k
# 商品的内容
print("{v[num]:<12} {v[name]:<12} {v[price]}".format(v=v))
# 报错信息
def error():
print("*" * 50)
print("*{val:^44}*".format(val="这是错误的选项"))
print("*" * 50)
time.sleep(0.5)
# 添加购物车
def add_car(num):
# 当前购买的商品不在购物车当中,那就添加购物车
if num not in car:
car[num] = {
"name":goods_lst[num-1]["name"],
"price":goods_lst[num-1]["price"],
"account":1
}
# 当前购买的商品在购物车当中,就在商品数量上做累加
else:
car[num]["account"] += 1
print(car)
# 展现购物车
def show_car(num):
print("*"*50)
print("您选择的商品具体信息")
print("*-商品名称:{}".format(car[num]["name"]))
print("*-商品单价:{}".format(car[num]["price"]))
print("*-商品数量:{}".format(car[num]["account"]))
print("*"*50)
print("已经成功添加到购物车~ 请继续shopping~")
# 计算价格
def balance():
total = 0
print("[-------------------您购物车的具体商品如下:-------------------]")
for k,v in car.items():
# 计算当前商品的总价格
cur_price = v["price"] * v["account"]
# 计算购物车中所有商品的总价格
total += cur_price
v["num"] = k
v["cur_price"] = cur_price
print("序号:{v[num]}: 商品名称:{v[name]} 商品单价:{v[price]} 商品数量:{v[account]} 商品总价:{v[cur_price]}".format(v=v))
return total
# 成功消息
def success(total,money):
print("正在结算数据中 ... ")
exe_process()
print("\n请稍后 ... ")
time.sleep(0.1)
print("[一共消费: {}元]".format(total))
# 剩余的金额 = 充值的金额 - 消费的金额
print("[您已成功购买以上所有商品,余额: {}元,感谢下次光临~]".format(money-total))
# 删除商品
def del_goods(total,money):
print("余额不足,还差{}元,请忍痛割爱,删除某些商品".format(total-money))
num = input("[-------------------请输入要删除的商品序号:-------------------]")
# 判断当前num是否纯数字字符串
if num.isdecimal():
num = int(num)
# 判断该序号是否是购物车中的数据
if num in car:
car[num]["account"] -= 1
# 如果数量已经减到0件,意味着从购物车中清空该数据
if not car[num]["account"]:
car.pop(num)
else:
error()
else:
error()
# 退出
def myexit():
print("[============== 欢迎下次光临: ==============]")
time.sleep(0.5)
def main():
# 1. 充值
recharge()
# 2. 加载中
loading()
# 3. 展示商品
show_goods()
# 4. 购买商品
sign = True
while sign:
num = input("请输入您要购买的商品(按q退出,按n结账):")
# 购买商品
if num.isdecimal():
num = int(num)
if 0 < num <= len(goods_lst):
# 添加购物车
add_car(num)
# 展现购物车
show_car(num)
else:
error()
# 计算商品价格
elif num.upper() == "N":
while True:
total = balance()
if total > money:
# 删除购物车中的商品
del_goods(total,money)
else:
# 打印成功的消息
success(total,money)
sign = False
break
# 按q退出
elif num.upper() == "Q":
# 退出
myexit()
sign = False
# 都不满足,直接报错
else:
error()
main()
ATM
bin 文件夹
# start 文件
# 启动程序入口
# 1. 将当前ATM项目工程,添加到解释器的环境变量
import os
import sys
from core import src
# 获取ATM的目录路径
base_path = os.path.dirname(os.path.dirname(__file__))
# 将项目路径添加到解释器的环境变量中
sys.path.append(base_path)
# 将试图层中的执行函数,引用到当前位置执行
if __name__ == '__main__':
# 执行src模块中的run函数
src.run()
conf 文件夹
# settings 配置文件
import os
# ATM根目录
BASE_PATH = os.path.dirname(os.path.diename(__file__))
# DB目录
DB_PATH = os.path.join(BASE_PATH,'db')
# 日志配置 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'
# 定义日志输出格式
LOG_DIR_PATH =os.path.join(BASE_PATH,'log')
LOG_FILE_NAME = 'access.log'
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(LOG_DIR_PATH):
os.mkdir(LOG_DIR_PATH)
# log文件的全路径
LOG_FILE_PATH = os.path.join(LOG_DIR_PATH,LOG_FILE_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': LOG_FILE_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': False, # 向上(更高level的logger)传递
},
},
}
core 文件夹
# admin 文件
from core import src
from lib import common
from interface import admin_interface
# 添加账户
def add_user():
src.register()
# 修改用户额度
def change_bal():
while True:
# 获取所有用户名
user_name_dic = common.get_user_dic()
if not user_name_dic:
print('没有用户可以修改')
break
for k,v in user_name_dic.items():
print(k,v)
# 让管理员选择
choice = input('请输入编号,选择需要修改的用户: ').strip()
username = user_name_dic.get(choice)
# 输入修改金额
limit = input('请输入要修改的额度: ').strip()
if not limit.isdigit():
print('金额必须是数字类型')
continue
limit = int(limit)
if choice in user_name_dic:
# 调用修改用户额度的接口
msg = admin_interface.change_bal_interface(username,limit)
print(msg)
break
else:
print('输入的编号有误!')
continue
# 冻结账户
def lock_user():
while True:
# 获取所有用户
user_name_dic = common.get_user_dic()
if not user_name_dic:
print('没有用户可以冻结')
break
for k,v in user_name_dic.items():
print(k,v)
# 让管理员选择
choice = input('请输入编号,选择需要冻结的用户: ').strip()
username = user_name_dic.get(choice)
# 调用管理员接口
msg = admin_interface.lock_user_interface(username)
print(msg)
break
# 解冻账户
def unlock_user():
while True:
# 获取所有用户名
user_name_dic = common.get_user_dic():
if not user_name_dic:
print('没有用户可以解冻')
break
for k,v in user_name_dic.items():
print(k,v)
# 管理员选择
choice = input('请输入编号,选择需要解冻的用户: ').strip()
username = user_name_dic.get(choice)
# 调用管理员接口
msg = admin_interface.unlock_user_interface(username)
print(msg)
break
# src 文件
# 用户视图层
from interface import user_interface
from interface import bank_interface
from interface import shop_interface
from lib import common
# 专门记录用户的登录状态
user_info = {
'user':None
}
# 1. 注册功能
def register():
while True:
# 让用户输入用户名和密码
username = input('请输入用户名: ').strip()
password = input('请输入密码: ').strip()
re_password = input('确认密码: ').strip()
# 逻辑判断
if password == re_password:
# 在视图层中调用注册接口,将用户与密码传递给注册接口做 核心逻辑处理
flag,msg = user_interface.register_interface(username,password)
if flag:
print(msg)
user_info['user'] = username
break
else:
print(msg)
else:
print('两次密码不一致,请重新输入!')
# 2. 登录功能
def login():
while True:
username = input('请输入用户名: ').strip()
password = input('请输入密码: ').strip()
# 登录接口
flag,msg = user_interface.login_interface(username,password)
if flag:
print(msg)
user_info['user'] = username
break
else:
print(msg)
# 3. 查看余额
@common.login_auth
def check_bal():
# 直接调用查询余额接口层,获取数据
bal = user_interface.check_bal_interface(user_info.get('user'))
print(f'当前用户的余额为: [{bal}]')
# 4. 提现功能
@common.login_auth
def withdraw():
# 提现,手续费5%
while True:
# 1. 需要提现的金额
balance = input('请输入要提现的金额: ').strip()
# 逻辑判断,是否是数字,若是数字强转为int类型
if not balance.isdigit():
print('请输入数字类型!')
continue
# str -> int
balance = int(balance)
# 2. 调用提现接口
flag,msg = bank_interface.withdraw_interface(user_info.get('user'),balance)
# 3. 打印接口返回结果
if flag:
print(msg)
break
else:
print(msg)
# 5. 还款功能
@common.login_auth
def repay():
while True:
# 让用户输入还款金额
money = input('请输入需要还款的金额: ').strip()
# 逻辑判断,是否是数字,若是数字则转为int类型
if not money.isdecimal:
print('请输入数字')
continue
money = int(money)
msg = bank_interface.repay_interface(user_info['user'],money)
print(msg)
break
# 6. 转账功能
@common.login_auth
def transfer():
while True:
target_user = input('请输入转账目标用户: ').strip()
money = input('请输入转账金额: ').strip()
if not money.isdigit():
print('请输入数字类型!')
continue
money = int(money)
flag,msg = bank_interface.transfer_interface(target_user,user_info['user'],money)
if flag:
print(msg)
break
else:
print(msg)
# 7. 查看流水
@common.login_auth
def check_flow():
# 直接调用查看 流水接口
flow_list = bank_interface.check_flow_interface(user_info['user'])
if flow_list:
for line in flow_list:
print(line)
# 8. 购物功能
@common.login_auth
def shopping():
cost = 0
shop_car = {}
while True:
# 循环打印商品列表信息,让用户选择商品编号
# 组织商品数据,并通过枚举打印
good_list = [
['电脑',3000],
['手机',5000],
['玩偶',100],
['香烟',30],
['水杯',180]
]
print('===========欢迎来到全家===========')
# 枚举 enumerate(good_list) -> return(索引,索引对应的值)
for index,good_l in enumerate(good_list):
# 组织商品打印格式
good_name,good_price = good_l
print(f'商品编号: {index} 商品名称: {good_name} 商品价格: {good_price}')
# 让用户选择商品编号
choice = input('请输入商品编号: ').strip()
# 判断当前用户输入的编号是否是数字
if not choice.isdigit():
print('请输入数字!')
continue
choice = int(choice)
# 判断当前用户输入的商品编号是否在商品列表的索引范围内
if not choice.isdigit():
print('请输入数字!')
continue
choice = int(choice)
# 判断当前用户输入的商品编号是否在商品列表的索引范围内
if choice not in range(len(good_list)):
print('编号有误,请重新输入!')
continue
# 获取用户选择的商品: 商品名,商品价格
good_name,good_price = good_list[choice]
# 添加购物车,当前用户每选择一个商品时,计算总价
# 若当前选择的商品不存在购物车中,则给商品数量设置初始值为1
if choice not in shop_car:
shop_car[choice] = {
'name':good_name,
'price':good_price,
'account':1
}
# 若当前选择的商品已经存在购物车,给商品数量加1
else:
shop_car[choice]['account'] += 1
print(f'商品名称: {shop_car[choice][name]} 商品价格: {shop_car[choice][price]} 商品数量: {shop_car[choice][account]}')
# 让用户输入 y 确认购买 调用结算接口 进行运算
# 输入 n 调用添加购物车接口 清空当前购物车字典 并退出购物功能
choice1 = input('y: 确认购买 n: 商品加入购物车并退出 输入 其他键 继续选择商品: ').strip()
cost = shop_car[choice]['price'] * shop_car[choice]['account'] + cost
if choice1.lower() == 'y':
# 调用支付接口
flag,msg = bank_interface.pay_interface(user_info['user'],cost)
if flag:
print(msg)
# 清空临时购物车
shop_car = {}
break
elif choice1.lower() == 'n':
# 调用添加购物车接口
msg = shop_interface.add_shop_car_interface(user_info['user'],shop_car)
print(msg)
# 清空临时购物车
shop_car = {}
break
# 9.查看购物车功能
@common.login_auth
def check_shop_car():
# 调用查看购物车接口
shop_car = shop_interface.check_shop_car_interface(user_info.get('user'))
print(shop_car)
# 10. 管理员功能
@common.login_auth
def admin():
from core import admin
admin_func_dic = {
'1':admin.add_user,
'2':admin.change_bal,
'3':admin.lock_user,
'4':admin.unlock_user
}
while Ture:
print('''
1. 添加账户
2. 修改用户额度
3. 冻结账户
4. 解冻账户
''')
choice = input('请输入功能编号: ').strip()
# 判断用户选择的编号是否在函数功能字典中
if choice not in admin_func_dic:
print('编号有误,请重新输入!')
continue
# func_dic.get('1') -> register()
admin_func_dic.get(choice)()
# 函数功能字典
func_dic = {
'1':register,
'2':login,
'3':check_bal,
'4':withdraw,
'5':repay,
'6':transfer,
'7':check_flow,
'8':shopping,
'9':check_shop_car,
'10':admin
}
# 提供给用户选择的函数
def run():
while True:
print('''
1.注册功能
2.登录功能
3.查看余额
4.提现功能
5.还款功能
6.转账功能
7.查看流水
8.购物功能
9.查看购物车功能
10.管理员功能
(q: 退出)
''')
choice = input('请输入要使用的功能编号: ').strip()
# 判断用户选择的编号是否在函数功能字典中
if choice not in func_dic:
if choice.lower() == 'q':
break
else:
print('编号有误,请重新输入!')
func_dic.get(choice)()
db 文件夹
# db_handler
# 数据层
import os
import json
from conf import settings
# 查看数据
def select(username):
# 以每个注册的'用户名'作为json文件名
# 用户json文件的路径
user_path = os.path.join(settings.DB_PATH,'%s.json'% username)
# 判断当前用户是否存在,os.path.exists(需要判断的文件路径)
if os.path.exits(user_path):
# 读取文件中的数据
with open(user_path,'r',encoding='utf-8') as f:
# f.read() -> json_str -> python
user_dic = json.load(f)
return user_dic
# 保存数据
def save(user_dic):
# 用户json文件路径
user_path = os.path.join(settings.DB_PATH,'%s.json' % user_dic['name'])
# 将数据写入文件中
with open(user_path,'w',encoding='utf-8') as f:
# dict -> json_str -> f.write(json_str) -> json文件
json.dump(user_dic,f,ensure_ascii=False)
#文件刷新
f.flush()
lib 文件夹
# common 文件夹
# 此处写公共方法
import os
import logging.config
from conf import settings
# 登录认证装饰器模板
def login_auth(func):
# 解决循环导入问题
from core import src
def inner(*args,**kwargs):
# 判断用户的登录状态,若有值代表已经登录,通过校验
if src.user_info.get('user'):
res = func(*args,**kwargs)
return res
else:
src.login()
return inner
def get_user_dic():
# 获取所有用户的名字,让管理员选择
# os.listdir(传递一个文件夹路径) -> 获取文件夹中所有文件的名字,放到一个列表
user_file_list = os.listdir(settings.DB_PATH)
# 存放用户名字的列表
user_name_dic = {}
num = 1
for user_file_name in user_file_list:
if user_file_name.endswith('.json'):
user_name = user_file_name.split('.')[0]
user_name_dic[str(num)] = user_name
num += 1
return user_name_dic
# 获取日志对象函数
def get_logger(user_type):
# 加载logging配置信息
logging.config.dictConfig(settings.LOGGING_DIC)
# 获取相关的 logger 对象
logger = logging.getLogger(user_type)
return logger
log 文件夹
# access.log
interface 文件夹
# admin_interface
# 管理员功能接口
from db import db_handler
from lib import common
admin_logger = common.get_logger('admin')
# 修改用户额度接口
def change_bal_interface(username,limit):
user_dic = db_handler.select(username)
user_dic['balance'] = limit
db_handler.save(user_dic)
admin_logger.info(f'修改用户[{username}]额度成功!')
return '修改成功'
# 冻结账户接口
def lock_user_interface(username):
user_dic = db_handler.select(username)
# 判断当前用户是否被锁定
if user_dic.get('locked'):
return '用户已经被锁定'
user_dic['locked'] = True
db_handler.save(user_dic)
return f'[{username}]用户锁定成功'
# 解冻账户接口
def unlock_user_interface(username):
user_dic = db_handler.select(username)
# 判断当前用户是否被锁定
if user_dic.get('locked'):
user_dic.['locked'] = Fasle
db_handler.save(user_dic)
return f'[{username}]用户解冻成功'
return '用户没有被锁定'
# user_interface
# 用户功能接口
from db import db_handler
from lib import common
user_logger = common.get_logger('user')
# 注册接口
def register_interface(username,password):
# 逻辑处理 -> 接口层
# 去数据处理层获取用户的数据
# user_dic -> user_dic / None
user_dic = db_handler.select(username)
# 若user_dic有数据,代表用户已存在
if user_dic:
return False,'用户已存在,请重新输入'
# 若用户不存在,则可以注册
# 组织用户数据,转成json数据保存到文件中
user_dic = {
'name':username,
'pwd':password,
'balance':15000,
'flow':[],
'shop_car':{},
'locked':False,
'admin':False
}
# 调用数据层中的保存数据功能save,将字典传递过去进行数据的保存
db_handler.save(user_dic)
user_logger.info(f'用户[{username}]注册成功')
# 返回注册结果给用户视图层
return True,f'用户[{username}]注册成功'
# 登录接口
def login_interface(username,password):
# 先去数据层,获取用户字典数据
user_dic = db_handler.select(username)
# 判断用户是否存在,若存在校验密码
if user_dic:
if password == user_dic.get('pwd'):
return True,f'用户[{username}]登录成功'
else:
return False,'密码错误,请重新输入'
# 若不存在,返回错误信息给视图层
else:
return False,'用户不存在,请重新输入'
# 查看余额接口
def check_bal_interface(username):
user_dic = db_handler.select(username)
return user_dic.get('balance')
# bank_interface
# 银行功能接口
import time
from db import db_handler
from lib import common
bank_logger = common.get_logger('bank')
# 提现接口
def withdraw_interface(username,money):
user_dic = db_handler.select(username)
# 判断用户账户金额 是否大于等于 提现金额 + 5% 手续费
money2 = money * 1.05
if user_dic.get('balance') >= money2:
# 给当前用户的金额减钱
user_dic['balance'] -= money2
# 制作一个流水
flow_str = f'{time.strftime('%Y-%m-%d %X')} 提现[{money}]成功! 手续费扣除[{money2-money}]'
# 记录日志
bank_logger.info(flow_str)
# 更新数据前,添加流水
user_dic['flow'].append(flow_str)
db_handler.save(user_dic)
return True,flow_str
else:
return False,'余额不足,请充值!'
# 还款接口
def repay_interface(username,money):
user_dic = db_handler.select(username)
# 直接加钱
user_dic['balance'] += money
flow_str = f'{time.strftime('%Y-%m-%d %X')} 还款[{money}]成功!'
# 记录日志
bank_logger.info(flow_str)
user_dic['flow'].append(flow_str)
db_handler.save(user_dic)
return flow_str
# 转账接口
def transfer_interface(target_name,login_name,money):
# 判断目标用户是否存在,若不存在,返回错误信息
target_user_dic = db_handler.select(target_name)
if not target_user_dic:
return False,'目标用户不存在'
# 若存在,获取当前用户数据
login_user_dic = db_handler.select(login_name)
# 判断当前用户金额 是否大于等于 转账金额
if login_user_dic.get('balance') >= money:
target_user_dic['balance'] += money
login_user_dic['balance'] -= money
flow_str1 = f'{time.strftime("%Y-%m-%d %X")} 用户:[{login_name}] 给 用户:[{target_name}] 转账 [{money}]元'
flow_str2 = f'{time.strftime("%Y-%m-%d %X")} 用户:[{target_name}] 接收到 用户:[{login_name}] 转账 [{money}]元'
login_user_dic['flow'].append(flow_str1)
target_user_dic['flow'].append(flow_str2)
# 数据修改后,更新数据,最后返回True,转账成功 给视图层
db_handler.save(target_user_dic)
db_handler.save(login_user_dic)
return True,'转账成功'
else:
return False,'账户金额不足,请充值'
# 查看流水接口
def check_flow_interface(username):
user_dic = db_handler.select(username)
if user_dic.get('flow'):
return user_dic.get('flow')
# 支付接口
def pay_interface(username,cost):
user_dic = db_handler.select(username)
if user_dic.get('balance') >= cost:
user_dic['balance'] -= cost
flow_str = f'{time.strftime("%Y-%m-%d %X")} 用户:[{username}] 购物支付金额为: [{cost}]'
user_dic['flow'].append(flow_str)
db_handler.save(user_dic)
return True,'支付成功'
else:
return False,'余额不足,请充值'
# 购物商场接口
from db import db_handler
from lib import common
shop_logger = common.get_logger('shop')
# 添加购物车接口
def add_shop_car_interface(username,shop_car):
user_dic = db_handler.select(username)
# 给当前用户字典的购物车 更新
# 先循环用户选择的临时购物车
for num in shop_car:
# 判断当前选择的购物车 是否有商品在用户字典的购物车中
if num in user_dic.get('shop_car'):
user_dic['shop_car'][num]['account'] += shop_car[num]['account']
else:
user_dic['shop_car'].update({num:shop_car[num]})
db_handler.save(user_dic)
shop_logger.info('添加购物车成功')
return '添加购物车成功'
# 查看购物车接口
def check_shop_car_interface(username):
# 获取当前用户的字典
user_dic = db_handler.select(username)
# 直接将购物车返回视图层
return user_dic.get('shop_car')