老男孩Day2作業:編寫購物車程序


作業要求

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM