作業要求
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('您的賬戶余額是\033[32m%d\033[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('您已成功充值,您的余額為\033[32m%d\033[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] + '\n') 219 # 所有二級菜單均添加到str1之后,在str1后面加上: 220 str1 += ':' 221 # 第二級死循環 222 while True: 223 # 分類來自於前面choose的交互式輸入,分類下面的列表來至於str1變量 224 # 讓用戶選擇一個二級菜單 225 c_name = input("請輸入您要選擇的%s分類名稱(輸入b返回,輸入q退出):\n%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 + '\n') 241 str2 += ':' 242 # 第三級死循環 243 while True: 244 # 在交互式界面,讓用戶輸入要購買的商品的名稱,商品目錄來自於str2變量 245 p_name = input('請輸入您要購買的商品名稱(輸入b返回上一級,q退出,h查詢購物車):\n%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('您目前的賬戶余額為\033[31m%d\033[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