作业要求
1、启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表
2、允许用户根据商品编号购买商品
3、用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒
4、可随时退出,退出时,打印已购买商品和余额
5、在用户使用过程中, 关键输出,如余额,商品已加入购物车等消息,需高亮显示
6、用户下一次登录后,输入用户名密码,直接回到上次的状态,即上次消费的余额什么的还是那些,再次登录可继续购买
7、允许查询之前的消费记录
1)编写思路
编写思路参考下面GitHub链接中的流程图
https://github.com/ChuixinZeng/PythonStudyCode/blob/master/PythonCode-OldBoy/Day2/作业/Day2_作业_购物车程序流程图.png
2)具体实现
1 # -*- coding:utf-8 -*- 2 3 # Author:Chuixin Zeng 4 5 # 导入JSON模块 6 import json 7 # 导入日期时间模块 8 import datetime 9 # 导入系统OS模块 10 import os 11 12 # 自定义欢迎信息 13 info = ''' 14 1. 按"A"注册 15 2. 按"B"登录 16 3. 按"Q"退出 17 ''' 18 # 自定义错误提示信息 19 _error_info = '输入有误,请检查后重新输入!' 20 21 # 定义一个_save_account函数 22 # 用于将购物相关信息保存到JSON文件,比如购物时间,购物历史,购物列表,账户余额,创建的新用户和现有已存在用户信息 23 def _save_account(database, filename='DataBase.json'): 24 # 打开并可写文件,若文件已存在,则以前的内容将被清除 25 # 使用with as语句的效率更高,不需要单独设置如何读文件之后再如何关闭文件,一个with as搞定所有读写关闭操作 26 with open(filename,'w') as f: # f相当于一个变量,把打开并修改文件的操作赋予f 27 json.dump(database,f) # json.dump是将一个Python数据类型列表进行json格式的编码解析 28 29 # 定义一个_load_database函数,用于从json文件中读取信息,默认加载的数据库是database.json文件 30 def _load_database(filename='DataBase.json'): 31 with open(filename) as f: 32 database = json.load(f) # 解码JSON数据,将一个JSON编码的字符串转换回一个Python数据结构 33 return database # 返回解码后的数据 34 35 # 定义一个函数_set_shopping_time,设置并记录购物的时间,函数里面定义了一个参数account,用于保存账户信息 36 def _set_shopping_time(account): 37 database = _load_database() # 设定要记录到哪个数据库,这里使用的是前面定义好的函数_load_database定义的database.json 38 d1 = datetime.datetime.now() # 设置购物时间为当前时间 39 d2 = d1.strftime('%Y-%m-%d %H:%M:%S') # 将当前时间进行格式转换 40 database[account]['shopping_time'] = d2 # 将转换好的时间记录到字典里面的shopping_time键上 41 _save_account(database) # 保存购物时间到数据库中,这里的数据库是指database.json文件 42 43 # 定义一个函数,用于获取已经保存过的购物时间 44 def _get_datetime(account): 45 database = _load_database() 46 data = database[account]['shopping_time'] 47 # 返回变量data的值,变量data保存的就是account键对应的购物时间值,这个值是从json里面解码出来后到字典里 48 # 由json到Python可识别的字典数据的解码过程由_load_database函数完成 49 return data 50 51 # 定义一个函数_get_shopping_history,用于查询购物历史记录 52 def _get_shopping_history(account): 53 database = _load_database() 54 history = database[account]['shopping_list'] 55 # 增加一个空列表,配合下边for循环将购物清单中的重复项合并 56 aa = [] 57 for i in history: 58 # 将购物车里面的shopping list和aa空列表进行对比,如果列表里面没有,就添加到列表 59 # 也就意味着,如果列表已经有了就不添加了,达到了购物车去重的功能 60 if i not in aa: 61 aa.append(i) 62 # 然后循环遍历aa列表里面的购物清单 63 for j in aa: 64 # 统计购买的每件商品的数量,也就是aa列表里面每件商品的数量,数量从history原始列表里面取(未去重的列表) 65 count = history.count(j) 66 # 统计购买商品的日期,日期就是account字典对应的商品的日期 67 date = _get_datetime(account) 68 # 打印购买的商品的数量、日期和商品名称 69 print('您于%s购买了%s件%s' %(date,count,j)) 70 71 # 定义一个函数login,用于登录系统 72 def _login(): 73 database = _load_database() # 加载数据库,使用的是前面定义好的加载数据库的函数 74 blacklist = _load_database('BlackList.json') # 设置用户的黑名单列表,在列表中的用户将不允许登录到购物系统 75 print('欢迎登录购物系统!') # 打印欢迎信息 76 # 第一个死循环 77 while True: 78 account = input("请输入您的账号登录系统(按q退出):") 79 if account in blacklist: 80 # 如果账户在黑名单里面,则退出登录 81 print("您的账号已经被锁定,请联系管理员处理!") 82 _logout() # 直接调用下面定义好的_logout()函数 83 # 判断如果用户输入的是q,就退出购物系统 84 elif account == 'q': 85 _logout() 86 # 判断如果用户在数据库里面,则继续判断用户输入的密码是否正确 87 # 这里使用while循环和count计数器,如果输入错误密码大于3次,则锁定账户 88 elif account in database: 89 count = 0 90 while count < 3: 91 pwd = input('请输入密码:') 92 # 如果用户输入的密码和数据库保存的密码匹配 93 if pwd == database[account]['pwd']: 94 # 进入到死循环 95 while True: 96 # 首先登录成功后,先获取用户账户的余额,告诉用户还剩多少钱,余额通过_get_balance函数得到 97 account_balance = _get_balance(account) 98 # 高亮打印账户的余额信息 99 print('您的账户余额是 33[32m%d 33[0m'% account_balance) 100 # 让用户输入特定字母进入特定的菜单,并使用strip去除提示信息前后的空格 101 command = input('按h查询购物历史,按s开始购物,按t充值,开始购物后购物历史将被清空:').strip() 102 # 导入用户购物信息数据库 103 database = _load_database() 104 # 判断如果用户输入的是h,则查询购物历史 105 if command == 'h': 106 # 判断如果购物时间不为空的话,证明用户有购买历史 107 if database[account]['shopping_time'] != None: 108 # 加载函数_get_shopping_history,输出购物历史信息 109 _get_shopping_history(account) 110 else: 111 print('您在本商城没有购买过东西!') 112 elif command == 't': 113 # 如果用户输入的是t,则加载定义好的_top_up函数,执行充值操作 114 _top_up(account) 115 elif command == 's': 116 # 如果用户输入的是s,则将字典中的购物列表和时间初始化为空 117 # 注意:这个字典是从json文件转换过来的,里面有历史数据,所以需要先清空 118 # 等用户购物完成后,新的字典数据,即购物数据,会写回到json文件 119 database[account]['shopping_list'] = [] 120 database[account]['shopping_time'] = None 121 # 调用_save_account函数,将清空的操作保存到database文件 122 _save_account(database) 123 # 调用shopping函数,开始购物 124 _shopping(account) 125 else: 126 # 如果用户的操作不符合上面所有的情况,则输出错误信息 127 # 这里直接调用前面定义好的_error_info函数,输出错误信息 128 print(_error_info) 129 else: 130 count += 1 131 # 告诉用户还有多少次机会尝试登陆 132 print('输入的密码错误,你还有%s机会' % (3 - count)) 133 # 将用户账号添加至blacklist,保存成字典形式,value设置为None 134 # 这里使用了字典的setdefalut用法,如果字典中包含有给定键,则返回该键对应的值,否则返回为该键设置的值 135 blacklist.setdefault(account) 136 # 用户输入三次错误操作之后,会跳出上面的while循环,然后打印信息告诉用户账号已锁定 137 print('您的账号已经锁定!') 138 # 将锁定的账户信息保存到黑名单列表 139 _save_account(blacklist,'BlackList.json') 140 # 调用退出登录的函数 141 _logout() 142 else: 143 print('账号不存在,请重试!或输入b返回上一层,输入q,退出购物程序!') 144 145 # 定义一个函数_set_shopping_list,用于设定购物清单 146 def _set_shopping_list(account,c_name,num): 147 database = _load_database() 148 # 使用for循环添加购买的商品的数量 149 for i in range(num): 150 # 将购买的商品添加到字典shopping_list键所对应的列表中 151 database[account]['shopping_list'].append(c_name) 152 # 将购买信息通过调用_save_account函数保存到json文件中 153 _save_account(database) 154 155 # 定义一个函数_set_balance,用于计算购买商品后,所剩下的余额 156 def _set_balance(account,num): 157 database = _load_database() 158 # 购买商品后,扣除购买的商品的价格 159 database[account]['balance'] -= num 160 # 将余额信息通过调用_save_account函数保存到json文件中 161 _save_account(database) 162 163 # 定义一个函数,用于执行充值操作 164 def _top_up(account): 165 database = _load_database() 166 # 进入循环 167 while True: 168 # 提供交互式界面让用户输入要充值的金额 169 num = input('请输入您要充值的金额:') 170 # 判断如果用户输入的是不是纯数字,则将充值后的金额更新到数据库 171 if num.isdigit(): # 判断输入是否为纯数字(充值的数据必须为纯数字) 172 database[account]["balance"] += int(num) # 将str格式的"纯数字"转换为int格式 173 _save_account(database) # 保存到文件 174 account_balance = _get_balance(account) # 再从文件中读取余额信息 175 # 高亮打印充值后的余额信息 176 print('您已成功充值,您的余额为 33[32m%d 33[0m元' % account_balance) 177 # 上面已经打印余额了,所以这里定义一个return none代表不使用return的方式返回余额 178 return None 179 180 # 如果用户输入的不是纯数字,则提示输入错误,重新进行while循环,让用户重新输入 181 else: 182 print('您的输入有误,请重新输入!') 183 184 # 定义一个函数_get_balance,用于获取账户余额 185 def _get_balance(account): 186 database = _load_database() 187 # 将字典中账户的余额信息读取到account_balance变量 188 account_balance = database[account]['balance'] 189 # 返回账户余额变量的值 190 return account_balance 191 192 # 定义一个函数_shopping,用于执行购物程序 193 def _shopping(account): 194 # 定义一个字典,用于保存商品菜单 195 goods = {'家电类': {'电视': {'小米电视': 3999, '乐视电视': 4299}, 196 '空调': {'格力空调': 8999, '海尔空调': 6000}, 197 '冰箱': {'美的冰箱': 5099, '西门子冰箱': 4599}}, 198 '3C类': {'电脑': {'联想笔记本': 6888, 'mac air': 8009}, 199 '手机': {'小米5': 1999, 'iPhone6': 5299}}, 200 '生活类': {'鞋子': {'NIKE篮球鞋': 899, '安踏': 399}, 201 'T恤': {'森马': 89, '真维斯': 75, '优衣库': 97}}} 202 # 第一级死循环 203 while True: 204 # 通过使用enumerate来直接循环到产品名称 205 for i in enumerate(goods.keys()): 206 # 打印第一级菜单 207 print(i) 208 # 提供交互式界面,让用户输入要选择的商品分类名称,选择一级菜单 209 choose = input('请输入您要选择的商品分类名称(输入q退出):').strip() 210 # 定义一个空字符串,用于保存二级菜单 211 str1 = '' 212 if choose in goods: 213 # 如果用户输入的商品分类正确,则将该商品分类下的所有商品打印出来 214 for i in enumerate(goods[choose].keys()): 215 # 打印用户选择的一级菜单下面的二级菜单 216 print(i) 217 # 将二级菜单追加添加到str1变量中 218 str1 += (i[1] + ' ') 219 # 所有二级菜单均添加到str1之后,在str1后面加上: 220 str1 += ':' 221 # 第二级死循环 222 while True: 223 # 分类来自于前面choose的交互式输入,分类下面的列表来至于str1变量 224 # 让用户选择一个二级菜单 225 c_name = input("请输入您要选择的%s分类名称(输入b返回,输入q退出): %s"% (choose, str1)).strip() 226 # 定义一个空字符串,用于保存三级菜单 227 str2 = '' 228 if c_name == 'b': 229 # 如果用户输入的是b,则中断当前的while循环,返回上上层循环,即返回到上层菜单 230 break 231 elif c_name == 'q': 232 # 如果用户输入的是q,则调用_log_out函数,退出登录 233 _logout(account) 234 # 如果用户输入的名称在二级菜单里面,则通过for把用户选择的二级菜单商品下面的三级菜单遍历出来 235 elif c_name in goods[choose]: 236 for i in goods[choose][c_name].keys(): 237 # 打印遍历出来的二级菜单下面的三级菜单,同时打印物品和价格 238 # i来自于keys即键名称(物品名称),goods[choose][c_name][i]取的是键的值,即价格 239 print(i,goods[choose][c_name][i]) 240 str2 += (i + ' ') 241 str2 += ':' 242 # 第三级死循环 243 while True: 244 # 在交互式界面,让用户输入要购买的商品的名称,商品目录来自于str2变量 245 p_name = input('请输入您要购买的商品名称(输入b返回上一级,q退出,h查询购物车): %s' 246 % str2).strip() 247 # 如果用户输入的是b,则跳出本层级的while死循环,退到上一级 248 if p_name == 'b': 249 break 250 # 如果用户输入的q,则直接调用_logout函数,退出购物 251 elif p_name == 'q': 252 _logout(account) 253 # 如果用户输入的h,则查询json文件中的购物历史 254 elif p_name == 'h': 255 database = _load_database() 256 # 有购物历史,则调用_get_shopping_history函数,输出购物历史 257 if database[account]['shopping_time'] != None: 258 _get_shopping_history() 259 # 梅花购物历史的话,则告诉用户无购物历史 260 else: 261 print('您在本商城没有购物记录!') 262 # 如果用户输入的商品名称在所选择的商品分类中 263 elif p_name in goods[choose][c_name]: 264 # 第四层死循环 265 while True: 266 # 交互式界面让用户输入要购买的商品的数量 267 num = input('请输入要购买的商品的数量:').strip() 268 # 如果用户输入的是纯数字 269 if num.isdigit(): 270 # 首先将纯数字转换为整型 271 num = int(num) 272 # 定义一个account_balance变量,保存现在的账户余额 273 account_balance = _get_balance(account) 274 # 定义一个价格变量,总价格 = 商品单价*数量,单价来自于字典,数量来自于num 275 price = (goods[choose][c_name][p_name]) * num 276 # 判断如果账户余额大于所购买的商品金额,才可以购买 277 if account_balance >= price: 278 # 调用_set_balance函数,计算购买后的账户余额是多少 279 # #计算方法在_set_balance函数里面 280 _set_balance(account,price) 281 # 提示用户已经成功购买商品 282 print('您成功购买%d件商品:%s!'% (num,p_name)) 283 # 调用_set_shopping_list函数,将购买的商品列表保存到json文件中 284 _set_shopping_list(account,p_name,num) 285 # 定义account_balance变量,通过使用_get_balance函数重新获取账户的余额信息 286 account_balance = _get_balance(account) 287 # 打印告诉用户,购买完商品之后剩下多少钱 288 print('您目前的账户余额为 33[31m%d 33[0m元' % account_balance) 289 # 调用_set_shopping_time函数,将购物时间写入到json文件 290 _set_shopping_time(account) 291 # 退出当前的循环,到上一级循环,用户可以选择是否继续购物 292 break 293 # 如果用户的账户余额小于商品的金额,则告诉用户余额不足,无法购买 294 else: 295 print('您的账户余额不足,请您及时充值!') 296 g = input("充值输入t,返回上一级输入b,退出输入q':") 297 if g == 'q': 298 _logout() 299 if g == 'b': 300 break 301 if g == 't': 302 # 这里我增加了一个调用_top_up函数,账户余额不住的时候,马上提示用户充值 303 _top_up(account) 304 # 如果用户购买商品时输入的数量不是纯数字类型,则调用_error_info函数,输出错误信息 305 else: 306 print(_error_info) 307 # 如果用户输入的购买的商品名称不正确,则调用_error_info函数,输出错误信息 308 else: 309 print(_error_info) 310 # # 如果用户输入的购买的商品分类信息不正确,则调用_error_info函数,输出错误信息 311 else: 312 print('输入错误,请重新输入!') 313 # 如果用户输入的不是商品分类,而是q,则调用_logout函数退出登录 314 elif choose == 'q': 315 _logout(account) 316 # 如果用户输入的信息既不在商品分类中,也不是q,则告诉用户重新输入 317 else: 318 print('输入错误,请重新输入!') 319 320 # 321 def _add_user(): 322 # 首先调用_load_database函数,将json文件解码出来,放到database变量 323 database = _load_database('DataBase.json') 324 # 执行while循环 325 while True: 326 # 提供交互式界面,让用户输入要创建的用户名称 327 username = input('请输入您的账户名称:').strip() 328 # 判断是否存在重名的用户,如果有,则告诉用户,继续执行while循环,让用户输入 329 if username in database: 330 print('用户名已经存在,不需要重复创建!') 331 # 如果没有,则用户输入信息有效,中断while循环 332 else: 333 break 334 # 执行while循环 335 while True: 336 # 让用户输入两次密码 337 pwd1 = input('请输入您的账户密码:').strip() 338 pwd2 = input('请再次输入您的账户密码:').strip() 339 # 对两次输入的密码信息进行比对 340 # 如果面膜不正确,则继续执行while循环让用户重新输入 341 if pwd1 != pwd2: 342 print('2次输入的密码不通,请重新输入') 343 # 如果输入的密码是正确的,则告诉用户创建账户成功 344 else: 345 print('创建用户成功,开始购物吧!') 346 # 把用户创建的账户和密码信息保存到database字典中 347 # username为用户账号,pwd1为用户密码,balance为账户余额,shopping_list为购物清单,shopping_time为购物时间 348 database[username] = {'pwd':pwd1,'balance':0,'shopping_list':[],'shopping_time':None} 349 # 调用_save_account函数,将创建好的账户信息和账户的初始余额、初始购物时间信息保存到json文件 350 _save_account(database) 351 # 退出while循环 352 break 353 354 # 设置默认变量account = None来判定账号是否已经登录,如果没有登录就退出,则不打印购物信息 355 # 如果已经登录过,则打印购物历史信息 356 def _logout(account=None): 357 if account != None: 358 _get_shopping_history(account) 359 exit('感谢您来购物!') 360 361 # 定义一个main函数,用于初始登录界面的判断 362 def main(): 363 # 执行while循环 364 while True: 365 # 打印登录提示信息,info信息定义在程序的开头,是一个字符串类型 366 print(info) 367 # 提供交互式界面,让用户输入指令信息 368 command = input('请输入指令:').strip() 369 # 如果用户输入的是大写的A,则调用_add_user函数,创建新用户 370 if command.upper() == 'A': 371 _add_user() 372 # 如果用户输入的是大写的B,则调用_login函数,进行登录 373 elif command.upper() == 'B': 374 _login() 375 # 如果用户输入的是Q,则调用_logout函数,退出登录 376 elif command.upper() == 'Q': 377 _logout() 378 # 如果用户没有按照提示信息进行输入,则告诉用户重新输入,会重新执行while循环 379 else: 380 print('输入错误,请重新输入') 381 382 # 执行main函数 383 if __name__ == '__main__': 384 main()
3)Github笔记
第二天的笔记的地址是:
https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day2/随堂练习
第二天作业的地址是:
https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day2/作业
4)Readme.md文档
https://github.com/ChuixinZeng/PythonStudyCode/blob/master/PythonCode-OldBoy/Day2/作业/Day2_作业_购物车程序Readme.md