# 作业二:请闭眼写出购物车程序
# #需求:
# 用户名和密码存放于文件中,格式为:egon|egon123
# 启动程序后,先登录,登录成功则显示用户余额,这时提示是否充值。失败则重新登录,超过三次则退出程序。
# 允许用户根据商品编号购买商品
# 用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒
# 可随时退出,退出时,打印已购买商品和余额
# 注意:1有账户可选择登录,无则注册后登录。
# 2下次登录后,余额是上次更改后的金额,即余额进行文件保存。
# 文件中用户信息存储为:
# "abc|123|0,qwe|123|1000"
# 将文件信息读取到内存中,以变量存储,因为1后期需要大量与这些信息交互(eg取值或修改),2为了降低跟硬盘文件打交道。
# 接着我如何设计存储用户信息的集合变量?
# 答:以用户名为key的dict,value可以为[]|{}。
users_dic = {} # 从文件中读取来
'''
{
'abc': {'ps': '123', 'money': 0},
'qwe': {'ps': '000', 'money': 1000}
}
'''
# 存储当前登录成功的用户的信息
user = {}
# {'usr': 'abc', 'ps': '123', 'money': 0}
# 获取所有已注册的用户,存放到user_dic。
# 获取文件中用户信息
def get_users():
# 如果用户集合已经有值,代表用户信息已经读取过了,不需要重复从硬盘文件读取用户信息。
if users_dic:
return users_dic
# 读文件,存用户们
with open('usr.info', 'rt', encoding='utf-8') as f:
# "abc|123|0,qwe|123|1000" or "abc|123|0" or none
data = f.read()
if not data:
# 文件中并没有用户信息,那么用户集合也不需要存储,可以直接返回
return users_dic
# ['abc|123|0', 'qwe|123|1000'] or ['abc|123|0']
data_list = data.split(',')
for d in data_list:
# ['abc', '123', '0']
user_info = d.split('|')
usr = user_info[0]
ps = user_info[1]
# 文件中读取的money为字符串,将money以数字存储在内存,方便购物等的运算。
money = int(user_info[2])
# 按照 'abc': {'ps': '123', 'money': 0} 存储到 users_dic
users_dic[usr] = {'ps': ps, 'money': money}
return users_dic
# 注册
def regist():
print("注册界面...")
# 获取所有用户信息
users = get_users()
# 账号输入操作
temp_info = "请"
while True:
usr = input(temp_info + "输入账号:").strip()
# 输入的用户名有格式问题
if not usr: # 用户名为空
print("账号不能为空!")
temp_info = "请重新"
continue
# 用户已存在
if usr in users:
print("用户已存在,请更换用户名!")
temp_info = "请重新"
continue
# 用户不存在,可以进入输入密码阶段
break #自己:有问题的判断代码在上面,最后写个break,这样写代码更简洁。
# 密码输入操作
temp_info = "请"
while True:
ps = input(temp_info + "输入密码:").strip()
# 输入的密码有格式问题
if len(ps) < 3:#密码为空或过短问题
print("密码过短!")
temp_info = "请重新"
continue
# ... 添加其他密码安全判断
break
# 账号密码均满足条件,可以注册(即写入文件)
with open('usr.info', 'at', encoding='utf-8') as f:
# 文件是否为空
# 为空abc|123|0 不为空,qwe|123|0
# 为什么逗号加在数据前面?
# 存为这样时sb, 123,
# with open('11.txt', 'r', encoding='utf-8')as f:
# res = f.read()
# res = res.split(',')
# print(res)
# 》》》['sb', '123', '']
# users是否为空可以直接反映文件是否为空
if users:
user_info = ',%s|%s|%d' % (usr, ps, 0)
else:
user_info = '%s|%s|%d' % (usr, ps, 0)
f.write(user_info)
# 文件操作完代表信息更新到文件中了,
# 还需要将信息更新到内存字典中
users[usr] = {'ps': ps, 'money': 0}
print('注册成功!')
# 登录
def login():
global user
print("登录界面...")
# 获取所有用户信息
users = get_users()
# 当前是否为登录状态
# 可以通过user(存储已登录账号)来反映是否为登录状态。
if user:
print("系统已经处于登录状态!")
return
# 用户名输入
temp_info = "请"
while True:
usr = input(temp_info + '输入账号:').strip()
# 账号不能为空
if not usr:
print("账号不能为空!")
temp_info = "请重新"
continue
# 账号不存在
if not usr in users:
print("输入用户名不存在")
# 文件为空,没有必要继续,不为空,可以让用户重新输入
if users:
temp_info = "请重新"
continue
return
break
# 输入密码操作
temp_info = "请"
count = 0
while count < 3:
ps = input(temp_info + '输入密码:').strip()
if users[usr]['ps'] == ps:
print('登录成功!')
# money在二次以后?,操作文件可能已经拥有金额???
money = users[usr]['money']
# how记录登录状态? 直接赋值代表覆盖,方法内局部变量不能直接覆盖全局变量,所以需要做global处理。
user = {'usr': usr, 'ps': ps, 'money': money}#方式1
# user['usr']=usr#方式2
# user['ps']=ps
# user['money']=money
break
print('密码输入错误!')
temp_info = "请重新"
count += 1
# 登录状态验证
def not_login():
if not user:
print('系统未登录!')
return True
#设计逻辑:未登录返回True,登录了返回None。
# 账户
def account():
if not not_login():#这句判断表示用户登录了,才会执行显示账户信息的操作。为何不用if user???
user_info = '账户:%s | 密码:%s | 金额:%d ' % (user['usr'], user['ps'], user['money'])
print(user_info)
#设计逻辑:判断登录状态。
# 用户登录了显示账户信息,未登录不执行任何操作(即不显示账户信息)这个条件的代码直接省略。
# 注销
def logout(): #def 函数名:if条件:操作子代码块 return实现省略else关键字。
# 因为return实现子代码块之后不会进行下面的操作,形成二选一操作的形式。
if not user:
print('系统未登录!')
return
user.clear()
print('注销成功')
# 登录成功后,对于商品的一系列操作
# 商品列表
goods_dic = {'1': 'iPhone', '2': 'Mac', '3': 'iPad'}
price_dic = {'iPhone': 100, 'Mac': 200, 'iPad': 50}
# 购物车
shop_car = {}
# {'iPhone': 3, 'iPad': 1}
goods_msg = '''
请添加商品到购物车:
1.iPhone | 2.Mac | 3.iPad | 0.退出购买'''
# 充值
def top_up():
if not user:
print('系统未登录!')
return
temp_info = "请"
while True:
money = input(temp_info + '输入充值金额:').strip()
if not money.isdigit():
print('输入金额有误!')
temp_info = "请重新"
continue
money = int(money)
break
# 更新金额
update_info('money', money)
print("充值完毕!")
# 对密码或金额进行修改
def update_info(k, v):#设置两个参数、变量名
# 修改金额后需要更新的内容有:
# 1.当前登录状态下的用户数据
# 2.内存中的用户们数据
# 3.文件中的用户信息
# 更新1号位
# 区分更新的类型
if k == 'money':
user[k] += v
else:
user[k] = v
# 为何要通过1号位更新2号位? #因为登录状态字典知道是针对哪个用户的修改
users = get_users()
users[user['usr']][k] = user[k]
# 为何要通过2号位更新3号位? #因为文件内容不能局部修改,只能全部覆盖来修改文件内容即'w'或者在末尾续写内容即'a'。
# 将
# {'abc': {'ps': '123', 'money': 0},'qwe': {'ps': '000', 'money': 1000}}
# 转换为
# "abc|123|0,qwe|123|1000"
# 写入文件
# 需要dict 转换为 str,怎么转换?自己:一次性实现,多步实现,借助工具。对象是个数据容器时怎么转变?是单个值时怎么转变?
users_info = ''
for k, v in users.items():
usr = k
ps = v['ps']
money = str(v['money'])
#user_info如何拼接多个用户数据?
if not users_info:
users_info += '|'.join((usr, ps, money))
else:
users_info += ',' + '|'.join((usr, ps, money))
# 转换完毕后便可以写入文件
with open('usr.info', 'wt', encoding='utf-8') as f:
f.write(users_info)
# 购物
def shopping():
if not user:
print('系统未登录!')
return
print(goods_msg)
while True:
# 商品编号
goods_num = input("商品编号:").strip()
if goods_num == '0':
print('退出购买!')
break
if not goods_num in goods_dic:
print('商品不存在!')
continue
while True:
# 商品数
count = input('商品个数:').strip()
if not count.isdigit():
print('个数有误!')
continue
count = int(count)
# 编号与个数均正确
# 加入购物车:{商品名: 个数}
goods = goods_dic[goods_num]
# 通过商品与购物车进行匹配,判断商品个数是累加还是赋值
if not goods in shop_car:
shop_car[goods] = count
else:
shop_car[goods] += count
# 更新完购物车后代表一次购物车添加完毕
# 查看一下当前购物车信息
shop_cart_info()
break
# 进入支付:余额充足直接付款,不足充值
pay_money()
# 购物车
def shop_cart_info():
if not shop_car:
print("购物车为空,可前往购物!!!")
return
print("购物车: ", shop_car)
# 支付
def pay_money():
if not user:
print('系统未登录!')
return
# 由购物来到支付,也可能主动调用支付
if not shop_car:
print("购物车为空,请前往购物!")
return
# 计算购物车内商品总价
total = 0
for goods in shop_car:
total += price_dic[goods] * shop_car[goods]
# 判断余额与商品总价大小
if user['money'] >= total:
print('余额充足,购买成功!')
# 更新信息
reduce = 0 - total
update_info('money', reduce)
# 支付成功后,需要清空购物车
shop_car.clear()
else:
print('余额不足,请充值!')
top_up()
# 系统功能提示信息
sys_msg = '''
欢迎使用购物车简单系统,请选择:
1.注册 | 2.登录 | 3.账户 | 4.充值 | 5.购物 | 6.支付 | 7.购物车 | 10.注销 | 0.退出
>>>'''
# 功能字典
method_dic = {
'1': regist,
'2': login,
'3': account,
'4': top_up,
'5': shopping,
'6': pay_money,
'7': shop_cart_info,
'10': logout
}
def system():
while True:
choice = input(sys_msg).strip()
# 退出选项
if choice == '0':
print("退出系统!")
return
# 错误选项
if not choice in method_dic:
print("功能输入有误,请重新输入")
continue
# 正确选项: eg: '1'-> regist
method_dic[choice]()
system()