python购物车小白详解
python购物车小白详解
编写思路
三大主体功能
注册
注册的重点在于存储用户注册的数据
我们目前要求是使用json格式将用户数据去存储到一个独立的用户数据文件夹(db)
在用户数据文件夹下,将以用户名作为文件名的文本文件存储到用户数据文件夹下。
难点:拼接绝对地址
创建db文件夹代码
coordinate = os.path.dirname(__file__) # 当前位置
db_path = os.path.join(coordinate, 'db') # db文件夹位置
if not os.path.exists(db_path): # db文件夹不存在
os.mkdir(db_path) # 创建
写入用户名文本代码
data_path = os.path.join(db_path, f'{username}.json') # 拼接用户地址
md5 = hashlib.md5() # 选择密码种类
md5.update(password.encode('utf8')) # 转换成md5
code = md5.hexdigest()
data_dict = {'username': username, 'password': code, 'balance': 15000, 'shop_car': {}}
# 编写默认数据字典
with open(data_path, 'w', encoding='utf8') as f1: # 重写功能打开
json.dump(data_dict, f1, ensure_ascii=False) # 写入json格式数据
登录
登录是基于注册之后的功能,依赖数据库中的用户文本文件去确定是否存在该用户和确定密码是否正确
需要让用户在成功登录一次之后,程序会记住用户登录状态和登录用户,这一步需要一个装饰器和一个全局变量。
难点:登录后改变全局变量
登录代码代码
def register(): # 登录
if name_state['name'] == None: # 双重确认
username = input('请输入您的姓名>>>:')
password3 = input('请输入您的密码>>>:')
name_path = os.path.join(db_path, f'{username}.json') # 拼接用户地址
if os.path.isfile(name_path): # 用户地址存在
res = get_data(username) # 使用函数获取用户数据,赋值给res
md5 = hashlib.md5() # 选择加密形式
md5.update(password3.encode('utf8')) # 将密码转换为md5码
code = md5.hexdigest() # 变量名去接收
if code == res.get('password'): # 判断是否相等
print('登录成功')
name_state['name'] = username # 改变状态全局变量
else:
print('密码错误')
else:
print('用户不存在')
装饰器代码
name_state = {'name': None} # 默认用户状态
def register0(func): # 判断是否登录的装饰器,配合状态全局变量使用
def register1():
if name_state['name'] == None: # 默认状态证明未登录,则会运行登录代码
print('请您先登录')
register()
else:
func()
return register1
购物
购物和结账
这一步应该是作为最复杂但也最简单的功能了,
复杂在于需要不断反复校验修改数据库数据,简单在于他只需要去修改单个用户文本文件夹就行。
只要前面的注册登录写好,这一步只不过是重复调用曾经学的索引取值。
难点:用户重复添加购物车,保存购物车元素,下次添加购物车时要将相同商品的数量累计。
商店函数
def shop(): # 超市
number = 0
basket = {} # 空篮子,很形象
while number != 8:
number = int(input('''
编号 商品名 单价
(1) 面 1
(2) 饼 5
(3) 木瓜 20
(4) 土豆 10
(5) 拌面 5
(6) 公仔 1000
(7) 玩偶 10000
(8) 退出并保存购物车
''').strip())
if number < 8:
quantity = int(input('输入您要购买的个数>>>:'))
if good_list[number-1][0] in basket: # 如果该物品在篮子中也有
quantity += basket[good_list[number-1][0]][0] # 同种类相加
basket[good_list[number-1][0]] = [quantity, good_list[number-1][1]] # 修改篮子内物品的数量
else:
basket[good_list[number-1][0]] = [quantity, good_list[number-1][1]] # 直接添加物品
if number == 8:
res = get_data(name_state['name']) # 用函数和状态全局变量获取当前用户数据
for i in basket: # 循环取出篮子中的k值
if i not in res['shop_car']: # 如果购物车不存在篮子中的k值
res['shop_car'][i] = [basket[i][0], basket[i][1]] # 直接加键值对
else:
res['shop_car'][i][0] += basket[i][0] # 购物车数量加上篮子中数量
else:
data_path = os.path.join(db_path, '%s.json' % name_state.get('name')) # 拼接用户地址
with open(data_path, 'w') as f1: # 重写模式
json.dump(res, f1, ensure_ascii=False) # 用json格式重写进去
结账函数
def pay(): # 结账
res = get_data(name_state.get('name')) # 调用函数获取用户数据
car = res.get('shop_car') # 取出购物车
price = 0
for i in car: # 循环取出购物车的k赋值给
price += car[i][0] * car[i][1] # 将购物车中物品依次数量与单价相乘
if res.get('balance') >= price: # 余额大于物品金额
bal = res.get('balance') - price # 获取购物后的金额
res['balance'] = bal # 用购物后金额去替换掉用户数据中的余额
data_path = os.path.join(db_path, '%s.json' % name_state.get('name')) # 拼接用户数据地址
with open(data_path, 'w') as f1: # w模式打开
json.dump(res, f1, ensure_ascii=False) # 用json格式写入
print('本次消费', price, '¥', '余额', bal) # 打印
res['shop_car'] = {} # 清空购物车
with open(data_path, 'w') as f1: # 写入空购物车
json.dump(res, f1, ensure_ascii=False)
日志模块
主要组成部分
1.logger对象:产出日志文件夹
logger = logging.getLogger('日志记录类型')
2.filter对象:过滤日志
handler自带了基本的过滤操作
3.handler对象:控制日志的输出位置(文件、终端...)
输出文件到文件夹中
log1 = logging.FileHandler('log.log',encoding='utf-8')
输出到控制台中
log2 = logging.StreamHandler()
4.format对象:控制日志的格式
自动获取时间,并按照时间参数格式。
复杂点的输出格式
fm = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
简洁点的输出格式
fm1 = logging.Formatter(
fmt='%(asctime)s - %(name)s: %(message)s',
datefmt='%Y-%m-%d',
)
5.给logger对象绑定handler对象(配合第3条)
logger.addHandler(log1) # 输出到文件夹中
logger.addHandler(log2) # 输出到控制台中
logger.addHandler(log1,log2) # 输出到文件和控制台中
6.给handler绑定formmate对象(配合第4条)
hd1.setFormatter(fm) # 输出复杂格式
hd2.setFormatter(fm1) # 输出简洁格式
7.设置日志等级
logger.setLevel(10) # debug,最低等级,每次运行都记录
8.记录日志
logger.debug('成功') # 类似于登录成功,注册成功,充值成功。
日志功能实际使用模板
配置字典模板
import logging
import logging.config
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', # 日志文件的编码,中文模式
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'],
# 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '注册记录': {
# 'handlers': ['console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger('记录类型')
'''loggers配置中使用空字符串作为字典的键 兼容性最好!!!'''
logger1.debug('成功类型')
购物车日志
将上述字典配置放到相对应的配置文件下settings.py文件中
然后根据下述方法去调用
import logging # 调用logging模块
import settings # 调用配置文件中,使用日志代码
def get_logger(msg): # 封装成函数放入公共文件夹,如果src.py可以实际去调用
# 记录日志
logging.config.dictConfig(setiing.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
# logger1.debug(f'{username}XX功能成功') # 获取用户输入
return logger1
目录规范
文件夹 | 文件名及后缀 | 功能 |
---|---|---|
bin文件夹 | start.py | 存放程序的启动文件(其他功能路径) |
conf文件夹 | settings.py | 存放程序的配置文件(生成日志等代码) |
core文件夹 | src.py | 存放程序的核心业务(登录、注册、购物等实际功能代码) |
lib文件夹 | common.py | 存放程序公共的功能(需要公共使用的功能,调用配置文件路径) |
db文件夹 | userinfo.txt | 存放程序的数据(各个用户的详细数据) |
log文件夹 | log.log | 存放程序的日志记录(记录实际功能运行的时间) |
readme文本 | readme.txt | 存放说明书 |
模块
启动程序
start.py文件需要的模块:
import src.py # 调用核心功能文件夹
或者
import sys
sys.path.append(os.path.dirname(__file__)) # 去通过环境变量添加实际功能地址
核心程序
src.py文件需要调用的模块:
import os # 操控文件模块
import json # 转换json格式模块
import hashlib # 加密模块
from common.py import get_logger # 从公共文件夹中去调用日志记录功能
import sys
sys.path.append(os.path.dirname(__file__)) # # 去通过环境变量添加实际功能地址
配置程序
settings.py文件需要的模块
import logging # 调用日志模块
import logging.config # 调用日志模块字典格式
公共程序
common.py文件需要的模块
import settings # 调用配置程序中的日志程序模块
import sys
sys.path.append(os.path.dirname(__file__)) # 或者去通过环境变量添加实际功能地址
数据文件夹
db.txt文本需要的模块
文本文件,无模块
主要负责存放json模块转换成json格式的文本文件
日志文件夹
log.log文本需要的模块
文本文件,无模块
主要负责存放日志代码产生的日志文本文件
补充
获取当前用户数据的函数
在购物车程序中,会频繁的需要获取当前用户的数据,合理的方式是编写成公共文件中,重复调用这个模块函数。
登录功能下的代码
name_state['name'] = username
def get_data(username): # 获取当前用户输入的详细资料的函数
data_path = os.path.join(db_path, f'{username}.json') # 拼接用户数据地址
with open(data_path) as f1: # 打开
res = json.load(f1) # 读取
return res # 返回
可直接配合当前登录状态去使用
res = get_data(name_state.get('name'))
调用函数主体功能
功能字典,内容也可以按照需求改成调用模块函数
func_dict = {
'1': register,
'2': login,
'3': shop,
'4': Shopping_cart,
'5': pay,
'6': recharge,
'7': exit
}
while True:
func_number = input('''
请输入您需要的功能编号
1.登录
2.注册
3.商店
4.购物车
5.结账
6.充值
7.登出
''')
if func_number in func_dict:
func_dict[func_number]()
充值功能
修改单个数据而已,很简单
def recharge(): # 充值
money = int(input('请输入您要充值的金额>>>:')) # 获取输入
res = get_data(name_state.get('name')) # 用函数获取用户输入
res['balance'] = res['balance'] + money # 余额与用户输入相加
data_path = os.path.join(db_path, '%s.json' % name_state.get('name')) # 获取用户数据绝对地址
with open(data_path, 'w') as f1: # 写入
json.dump(res, f1, ensure_ascii=False)
print('本次充值', money, '余额', res['balance'])
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!