python闯关_Day012

day012 用python实现信息卡管理及购物商城的项目

 

需求

#需求:
1 这是一个信用卡管理程序
2 用户手持信用卡购物,使用函数,按照软件开发规范
3 用户名密码存放于文件中,支持多用户登陆,使用json
4 程序启动,先登录或者注册,保存信息到文件中,记录日志
5 用户的登陆,密码输错三次,锁定,不能再登录
6 用户可以取现,消费,还款,提额
7 允许用户根据商品编号购买商品,用户选择商品,检测余额,够用扣款,不够用提示,用户行为都要记录日志
8 用户可以随时退出,退出时,打印已购买商品和余额

借鉴了老师在day011中的代码框架,添加了部分代码。

 

项目的结构如下。

 

项目的目录结构如下。

 

项目的运行结果展示

 

待改进的地方

1.  未做到单点登录
2.  日志的信息不够详细
3.  项目的健壮性,输入校验等等,有待提高

代码如下。

#/bin/start.py
import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)from core import srcif __name__ == '__main__':src.run()

  

#/conf/setting.pyimport osBASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PATH=os.path.join(BASE_DIR,'db','db.json')
LOG_PATH=os.path.join(BASE_DIR,'log','access.log')
LOGIN_TIMEOUT=3"""
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配置字典
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_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)传递},},
}

  

#/core/src.pyfrom conf import settings
from lib import common
import timelogger=common.get_logger(__name__)current_user={'user':None,'login_time':None,'timeout':int(settings.LOGIN_TIMEOUT)}def auth(func):def wrapper(*args,**kwargs):if current_user['user']:interval=time.time()-current_user['login_time']if interval < current_user['timeout']:return func(*args,**kwargs)name = input('name>>: ')db=common.conn_db()if db.get(name):   #已注册用户的登录流程if db.get(name).get('locked'):logger.warning('该用户已被锁定')print ('该用户已被锁定')else:logging_error_times = 0while True:if logging_error_times >= 3:logger.warning('密码输入错误3次,该用户已被')db[name]['locked'] = 1common.save_db(db)breakpassword = input('password>>:')if password == db.get(name).get('password'):logger.info('登录成功')print('登录成功')current_user['user'] = namecurrent_user['login_time'] = time.time()return func(*args, **kwargs)else:logger.warning('密码错误')logging_error_times += 1else:           #注册is_register = input('是否注册? (Y/N)')if is_register in ['Y','y']:password = input('password>>')db[name] = {"password":password, "money":0, "locked":0}logger.info("登录成功")print('登录成功')current_user['user'] = namecurrent_user['login_time'] = time.time()common.save_db(db)return func(*args, **kwargs)else:logger.info('用户不注册')return wrapper@auth
def buy():db = common.conn_db()money = db.get(current_user['user']).get('money')print ('目前账户有%d元' %money)items_dict = {'item1':1, 'item2':2}print (items_dict.keys())items_bought_dic = {}while True:item_buy = input('buy which(Q退出)?>>').strip()item_buy_split = item_buy.split(' ')#print (item_buy_split[0], item_buy_split[1])if item_buy_split[0] in ['q', 'Q']:db[current_user['user']]['money'] = moneycommon.save_db(db)print('你买了:',items_bought_dic)print('账户余额:',money)breakelif item_buy_split[0] in items_dict:item, item_num = item_buy_split[0], item_buy_split[1]item_price = items_dict[item] * int(item_num)print(item,':',item_num,'共花了%d'%item_price)if item_price <= money:money -= item_priceprint ('购买成功,还有%d元'%money)if item in items_bought_dic:items_bought_dic[item] += item_numelse:items_bought_dic[item] = item_numelse:print ('余额不足')else:print ('请输入:【商量名称】 【商品数量】')@auth
def withdraw():db = common.conn_db()money = db.get(current_user['user']).get('money')print ('账户余额%d元' %money)withdraw_num = int(input('取多少钱?'))if withdraw_num <= money:money -= withdraw_numdb[current_user['user']]['money'] = moneycommon.save_db(db)print ('取现成功,账户余额%d' % money)else:print ('账户余额不足')@auth
def repay():db = common.conn_db()money = db.get(current_user['user']).get('money')print('账户余额%d元' % money)repay_num = int(input('还款数量? '))money += repay_numdb[current_user['user']]['money'] = moneycommon.save_db(db)print('还款成功,你还有%d' % (money))@auth
def run():print('''
1. 取现
2. 还款
3. 消费
Q. 退出''')while True:choice = input('>>: ').strip()if not choice:continueif choice == '1':withdraw()if choice == '2':repay()if choice == '3':buy()if choice in ['Q','q']:quit()

  

#/db/db.json
{"user1": {"password": "111", "money": 2705, "locked": 0}, "user2": {"password": "111", "money": 30000, "locked": 0}, "user3": {"password": "111", "money": 20000, "locked": 0}, "zjl": {"password": "111", "money": 0, "locked": 0}}

  

#/lib/common.pyfrom conf import settings
import logging
import logging.config
import jsondef get_logger(name):logging.config.dictConfig(settings.LOGGING_DIC)  # 导入上面定义的logging配置logger = logging.getLogger(name)  # 生成一个log实例return loggerdef conn_db():db_path=settings.DB_PATHdic=json.load(open(db_path,'r',encoding='utf-8'))return dicdef save_db(dic):db_path = settings.DB_PATHjson.dump(dic, open(db_path, 'w', encoding='utf-8'))

  

日志的截图

 

转载于:https://www.cnblogs.com/marathoner/p/10273662.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

http:(3):http响应头信息

HTTP 响应头信息 HTTP请求头提供了关于请求&#xff0c;响应或者其他的发送实体的信息。 在本章节中我们将具体来介绍HTTP响应头信息。 应答头 说明 Allow 服务器支持哪些请求方法&#xff08;如GET、POST等&#xff09;。 Content-Encoding 文档的编码&#xff08;En…

php 强制刷新一次,强制浏览器使用PHP刷新所有内容

一个问题&#xff0c;特别是在创建AJAX应用程序时&#xff0c;是浏览器可以缓存页面的内容&#xff0c;以便在发出类似请求时&#xff0c;可以呈现相同的内容。要强制浏览器显示所需内容而不进行缓存&#xff0c;可以在页面中添加以下标题。header("HTTP/1.1 202 Accepted…

[Leedcode][JAVA][第1248题][统计「优美子数组][找规律]

【问题描述】 1248. 统计「优美子数组」 给你一个整数数组 nums 和一个整数 k。如果某个 连续 子数组中恰好有 k 个奇数数字&#xff0c;我们就认为这个子数组是「优美子数组」。请返回这个数组中「优美子数组」的数目。 示例 1&#xff1a;输入&#xff1a;nums [1,1,2,1,1]…

[ubuntu setting]Change system language

1.Open the software "语言支持". ​ 2.Then select "English" lauguage, an apply to whole system. ​ 3.reboot system. [end]转载于:https://www.cnblogs.com/lizhuohui/p/10274356.html

http:(4):http请求方法

HTTP 消息结构 HTTP是基于客户端/服务端&#xff08;C/S&#xff09;的架构模型&#xff0c;通过一个可靠的链接来交换信息&#xff0c;是一个无状态的请求/响应协议。 一个HTTP"客户端"是一个应用程序&#xff08;Web浏览器或其他任何客户端&#xff09;&#xff…

oracle控制文件全备失败,Oracle数据库案例整理-恢复数据库失败-主备机控制文件所在目录不同...

1.1 现象描述使用主机节点的控制文件在备机节点上进行恢复时失败。 主节点控制文件目录为&#xff1a;“/opt/HUAWEI/cgp/workshop/omu/database/control_file/f0s11”。控制文件为&#xff1a;-rwxrwxr-x 1 oracle oinstall 10043392 Apr 23 14:11 control01.ct…

[Leedcode][JAVA][第199题][二叉树的右视图][BFS][DFS][前中后序遍历]

【问题描述】199.二叉树的右视图 给定一棵二叉树&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。示例:输入: [1,2,3,null,5,null,4] 输出: [1, 3, 4] 解释:1 <---/ \ 2 3 <---\…

基于声音的击键信号识别

摘要 本文文章采用击键信号的短时能量及峰值片段的幅度及各个幅度对应的频率作为特征向量。采用声音搜集装置搜集敲击键盘产生的声音信号&#xff0c;并对声音信号进行巴特沃斯滤波方法进行滤波预处理&#xff1b;将上述经过滤波得到的信号减去环境背景信号&#xff0c;得到当…

http:(5):http状态码

HTTP状态码 当浏览者访问一个网页时&#xff0c;浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前&#xff0c;此网页所在的服务器会返回一个包含HTTP状态码的信息头&#xff08;server header&#xff09;用以响应浏览器的请求。 HTTP状态码的英文为HTT…

oracle怎么从大字段中取节点,Oracle数据库 获取CLOB字段存储的xml格式字符串指定节点的值...

参照: Oracle存储过程中使用游标来批量解析CLOB字段里面的xml字符串背景:在写存储过程时,需要获取表单提交的信息。表单信息是以xml格式的字符串存储在colb类型的字段dataxml中&#xff0c;如何获取呢&#xff1f;参考百度内容&#xff0c;写一个function(函数)&#xff0c;参数…

[爬虫][python][入门][网页源码][百度图片][豆瓣TOP250]

Robots协议 查看爬取规则 遵守相关法律法规 Robots协议&#xff08;也称为爬虫协议、机器人协议等&#xff09;的全称是“网络爬虫排除标准”&#xff08;Robots Exclusion Protocol&#xff09;&#xff0c;网站通过Robots协议告诉爬虫哪些页面可以抓取&#xff0c;哪些页面不…

mysql(1):查找语句练习

1创建一个员工表 CREATE TABLE employees ( emp_no int(11) NOT NULL, birth_date date NOT NULL, first_name varchar(14) NOT NULL, last_name varchar(16) NOT NULL, gender char(1) NOT NULL, hire_date date NOT NULL, PRIMARY KEY (emp_no)); 2插入数据 insert into em…

CSS基础选择器(选择器的优先级),CSS样式块( 长度/颜色/显示方式/文本样式),盒模型组成,盒模型-block,盒模型布局...

CSS基础选择器 &#xff08;1&#xff09;id选择器: # 》 标签拥有 id"user" 属性 <style>#user {width: 200px;}</style><div id"user"></div> &#xff08;2&#xff09;( class ) 类选择器 : . 》 标签拥有 …

resin php extensions sockets,linux 有关笔记

linux 相关笔记系统安装1.启动服务器2.10秒内按F10进入DELL UNIFIED SERVER CONFIGURATION3.进入左侧OS Deployment菜单4.点击右侧Deploy OS链接5.插入Cent OS 5.5 x64光盘6.选择 Red Hat Enterorise Linux 5.5 64-bit,点击next7.在 Insert OS Media(Step 2 of 3) 页面 点击nex…

[Leedcode][JAVA][面试题 08.11][硬币][动态规划]

【问题描述】 面试题 08.11.硬币 硬币。给定数量不限的硬币&#xff0c;币值为25分、10分、5分和1分&#xff0c;编写代码计算n分有几种表示法。(结果可能会很大&#xff0c;你需要将结果模上1000000007)示例1:输入: n 5输出&#xff1a;2解释: 有两种方式可以凑成总金额: 55…

Install/Remove of the Service Denied错误解决

Windows安装mysql Install/Remove of the Service Denied 在windos 的cmd下安装mysql 在mysql的bin目录下面执行&#xff1a; mysqld --install 报错&#xff1a; 信息如下&#xff1a; Install/Remove of the Service Denied 解决办法&#xff1a; 打开cmd.exe程序的时候…

Java课程设计

目录 Magic-Towers一、团队课程设计博客链接团队博客地址二、个人负责模块或任务说明三、自己的代码提交记录截图四、课程设计感想Magic-Towers 一、团队课程设计博客链接 团队博客地址 二、个人负责模块或任务说明 任务分配  网络1713柳聪灵【组长】--Model游戏布局及障碍物的…

玩转oracle 11g(44):数据库发展历史

数据库发展历史 数据库技术从 20 世纪 60 年代开始到现在一共经历了三个发展阶段&#xff1a;  第一代是网状、层次数据库系统 网状 &#xff1a;通用电气公司 Bachman 等人在 1961 年开发成功的 IDS 层次 &#xff1a; IBM 公司在 1968 年开发的 IMS 第二代是关…

linux系统命令光标移动,Linux 命令行 光标移动技巧及利用grep和find查找文件内容...

从文件内容查找匹配指定字符串的行&#xff1a;$ grep “被查找的字符串” 文件名例子&#xff1a;在当前目录里第一级文件夹中寻找包含指定字符串的.in文件grep “thermcontact” /.in从文件内容查找与正则表达式匹配的行&#xff1a;$ grep –e “正则表达式” 文件名查找时不…

[Java学习资料] [成长之路]

[背景] 网上学习资料千千万万&#xff0c;成长之路千千万万&#xff0c;各取所需 JAVA基础 网站 https://www.runoob.com/java/java-tutorial.html https://www.w3cschool.cn/java/dict 公众号 书籍 算法 网站 labuladong https://github.com/labuladong/fucking-algo…