Python 基础 - Day 5 Assignment - ATM
作業(yè)需求及初步思路
| ? | 需求? | 思路? |
| 1 | 自定義信用卡額度 e.g 15000? | ?見下數(shù)據(jù)存儲模式 |
| ?2? | 實現(xiàn)購物商城,買東西加入購物車,調(diào)用信用卡結(jié)構(gòu)結(jié)賬 | ?改下購物車的扣款接口? |
| 3 | 可以提現(xiàn),手續(xù)費5% ? | 【提現(xiàn)】注意有利息,同時打印日志? |
| 4 | 支持多賬戶登陸(admin, client) | 【信用卡中心】for client 【管理員中心】for admin |
| 5 | 支持賬戶間轉(zhuǎn)賬? | 【轉(zhuǎn)賬】打印日志? |
| ?6 | 記錄每月日常消費流水? | 【消費流水】transaction.log; 呈現(xiàn)購物車消費,提現(xiàn),轉(zhuǎn)賬,還款的日志? |
| ?7 | 提供還款結(jié)構(gòu)? | 【還款】? |
| ?8 | ATM記錄操作日志 | access.log; 呈現(xiàn)賬戶操作日志? |
| ?9 | 提供管理接口(admin),包括添加賬戶、用戶額度、凍結(jié)賬戶等? | 【管理員中心】 |
| 10 | 用戶認(rèn)證用裝飾器? | 登陸之后,在其他接口時,用于驗證登陸狀態(tài) |
知識點
1. 程序的解耦:以下引用知乎的一個解釋
解耦即增加正交性,通俗的講就是減少模塊間的互相干擾,讓各個模塊的修改變化盡可能小的影響其它模塊。
完全不耦合是不可能的,完全不耦合的程序不可能進(jìn)行數(shù)據(jù)和指令的傳遞與交換。
解耦的基本方法是面向接口進(jìn)行開發(fā),也就是說各個模塊只和接口發(fā)生耦合,要么調(diào)用接口要么實現(xiàn)接口,因此接口本身的設(shè)計是程序模塊化的重中之重,大型程序中接口設(shè)計的優(yōu)劣常常直接決定整個系統(tǒng)的優(yōu)劣。
一個常見且基本的例子是圖形處理。在正交的程序中,當(dāng)你得到一個shape對象,可以通過該對象的draw方法直接把它畫出來,而不必關(guān)心它實際上是一個 circle,rectangle,還是triangle。而在一個非正交的程序中,你必須分別知道它們的圓心位置和半徑,長和寬,各頂點位置等信息再進(jìn)行具體的繪制。簡單說,前一種情況只依賴了draw方法,而后一種情況需要依賴各個圖形的具體參數(shù)。 在ATM作業(yè)中,比較典型的解耦例子:auth 和 transaction??
2. 多線程操作下的文件存儲方式:每個client account 建立一個 json文件。 目的是,當(dāng)某個用戶在操作賬戶時,另一個客戶也可以同時操作更改賬戶信息。?
?
3. 數(shù)據(jù)類型接口: 為了能夠?qū)硬煌臄?shù)據(jù)庫,一般設(shè)置鑒別數(shù)據(jù)存貯的方式。 具體操作是,在conf/settings中,設(shè)置以下database的字典。這種操作和Django里一樣。 這樣操作主要是為了任意更換數(shù)據(jù)庫類型, 可以是file, mysql, postegresal等。?
DATABASE = dict(engine="file_storage", # engine為數(shù)據(jù)庫類型;可擴(kuò)張成不同數(shù)據(jù)源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"database"), # 數(shù)據(jù)庫路徑name="accounts") # 數(shù)據(jù)庫名稱,每個數(shù)據(jù)庫一個json文件,為了支持多線程操作。數(shù)據(jù)庫接口代碼如下:?
但是,寫數(shù)據(jù)庫接口 db api 中,要注意統(tǒng)一不同數(shù)據(jù)庫的解析語言(mysql)。接口對象有:
?
4. logging 模塊: 寫入不同的文件(handler); 讀取日志,有條件地讀取日志信息(show_logger)
?
MY WORK
?
#!usr/bin/env python #-*- coding:utf-8 -*-import os import sysBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR)from core import mainif __name__ == '__main__':main.sys_run() bin\atm.py?
#!usr/bin/env python #-*- coding:utf-8 -*-import os, sys, logging# 主程序目錄 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 數(shù)據(jù)庫 DATABASE = dict(engine="file", # engine為數(shù)據(jù)庫類型;可擴(kuò)張成不同數(shù)據(jù)源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"database"),name="accounts") # 數(shù)據(jù)庫名稱,每個數(shù)據(jù)庫一個json文件,為了支持多線程操作。# 日志 LOG_LEVEL = logging.INFO LOG_TYPES = dict(transactions="transactions.log",access="access.log")LOG_DATABASE = dict(engine="file", # 可擴(kuò)張成不同數(shù)據(jù)源如mysql, postegresal等database_path= os.path.join(BASE_DIR,"log"),name="accounts")# 參數(shù) BILL_DAY = 22TRANSACTION_TYPE = {'repay': {'action': 'plus', 'interest': 0}, # 還款'receive': {'action': "plus", 'interest': 0}, # 接收'withdraw': {'action': 'minus', 'interest':0.05}, # 提款'transfer': {'action': 'minus', 'interest':0.05}, # 轉(zhuǎn)出'pay': {'action': 'minus', 'interest': 0}, # 支付 }SHOPPING_MENU = {'海鮮水產(chǎn)':{'竹節(jié)蝦': {'單價': 68, '數(shù)量': 5},'面包蟹': {'單價': 75, '數(shù)量': 5},'石斑魚': {'單價': 50, '數(shù)量': 5},'活蟶子': {'單價': 20, '數(shù)量': 10}},'新鮮水果':{'陽山水蜜桃': {'單價': 33, '數(shù)量': 5},'8424西瓜': {'單價': 60, '數(shù)量': 5},'巨峰葡萄': {'單價': 21, '數(shù)量': 5},'仙居楊梅': {'單價': 40, '數(shù)量': 5},'小臺農(nóng)芒果': {'單價': 13, '數(shù)量': 20}},'肉禽蛋品': {'土雞蛋': {'單價': 9, '數(shù)量': 4},'澳洲上腦牛排': {'單價': 30, '數(shù)量': 5},'黑毛豬小排': {'單價': 28, '數(shù)量': 5},'澳洲冰鮮牛腩': {'單價': 45, '數(shù)量': 5},'帝王雞': {'單價': 100, '數(shù)量': 5}},'乳制品': {'低脂鮮牛奶': {'單價': 17, '數(shù)量': 5},'全脂牛奶': {'單價': 20, '數(shù)量': 4},'酸奶': {'單價': 21, '數(shù)量': 2}}} conf\settings #!usr/bin/env python #-*- coding:utf-8 -*- OPEN_WIN = ''' |------------------------------------MyBank\'s ATM SYSTEM--------------------------------------| | | | 1. Admin | | 2. Existing Client | | | | Please contact our local service counter for a new credit card application. | |----------------------------------------------------------------------------------------------| '''CLIENT_WIN = ''' |------------------------------------MyBank\'s ATM SYSTEM--------------------------------------| | Dear {}, | | 1. Online Shopping 2. My Account 3. Repayment | | 4. Withdrawal 5. Transfer 6. Account Statement | | 7. Log Out | | | |----------------------------------------------------------------------------------------------| '''ADMIN_WIN = ''' |------------------------------------MyBank\'s ATM SYSTEM--------------------------------------| | Dear {}, | | 1. Create 2. Reactivate 3. Freeze | | 4. Credit update 5. Log Out | | | | | |----------------------------------------------------------------------------------------------| '''STATEMENT_TEMP = ''' |---------------------------------------------------STATEMENT REPORT----------------------------------------------------|Dear {},Your desired reporting period: \033[31;1m{}\033[0m to \033[31;1m{}\033[0m |-----------------------------------------------------------------------------------------------------------------------| '''SHOPPING_WIN = ''' |--------------------------MyBank\'s Online Shopping Mall--------------------------------------| | Dear {}, | | 1. Shopping 2. Historical shopping log | | | | | |----------------------------------------------------------------------------------------------| ''' conf\templates 1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import os,json,datetime 5 from conf import settings 6 from core import db_handler 7 from core import update_acc_info 8 from core import logger 9 10 def login(user_data, log_type): 11 ''' 12 系統(tǒng)登錄,將讀取的json信息作為account_data 更新到user_data 字典中去 13 :param user_data: from main 14 :return: 15 ''' 16 login_count = 0 17 max_count = 3 18 account_id = input("Accout ID: ").strip() 19 while user_data["is_authenticated"] is not True: 20 if login_count < max_count: 21 password = input("Password: ").strip() 22 acc_file = "%s.json" % account_id 23 db_file_path = db_handler.db_handler(settings.DATABASE) 24 acc_path = os.path.join(db_file_path, acc_file) # 獲取單個acc 路徑,支持多線程操作 25 if os.path.isfile(acc_path): 26 with open(acc_path, "r+", encoding="utf-8") as f: 27 account_data = json.load(f) 28 if account_data["password"] == password: 29 exp_date_stamp = datetime.datetime.strptime(account_data["expire_date"], "%Y-%m-%d") 30 acc_status = account_data["status"] 31 if acc_status == 0 or acc_status == 8: 32 if exp_date_stamp < datetime.datetime.today(): 33 print("Your account is expired. please contact admin for renew.") 34 else: 35 return account_data 36 else: 37 exit("Your account is frozen. Please contact admin for updates") 38 else: 39 print("Incorrect password ") 40 login_count +=1 41 continue 42 else: 43 exit("Account does not exit! Please contact admin") 44 else: 45 log_type.error("account is frozen for trying too many times") 46 account_data = update_acc_info.load_account(account_id) 47 account_data["status"] = 2 48 update_acc_info.dump_account(account_data) 49 exit() core\auth 1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import datetime 5 from conf import settings 6 7 def get_bill_date(year_month): 8 ''' 9 獲取賬單時間內(nèi)的賬單。每月賬單日22日 10 :param year_month_date: 11 :return: 12 ''' 13 bill_day = "%s-%s" % (year_month, settings.BILL_DAY) 14 bill_bday = datetime.datetime.strptime(bill_day, "%Y-%m-%d") 15 year = bill_bday.year 16 month = bill_bday.month 17 if month == 12: 18 year +=1 19 month =1 20 else: 21 month +=1 22 bill_eday = datetime.datetime(year, month, settings.BILL_DAY) 23 return bill_bday,bill_eday core\billdate 1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 5 def db_handler(conn_params): 6 ''' 7 數(shù)據(jù)庫接口解析。可擴(kuò)展到mysql, postgresql等其他數(shù)據(jù)庫方式。現(xiàn)在只用file 存儲 8 :param conn_params: settings.DATABASE 9 :return: file讀取,返回數(shù)據(jù)庫路徑 10 ''' 11 if conn_params["engine"] == "file": 12 return conn_params["database_path"] 13 else: 14 print('Current system does not support other databases') core\db_handler 1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import logging 5 import os 6 import datetime 7 from conf import settings 8 from conf import templates 9 from core import billdate 10 11 def logger(log_type): 12 ''' 13 寫日志到屏幕和不同文件 14 :param log_type: transaction 或 access 15 :return: 16 ''' 17 # 創(chuàng)建logger 18 logger = logging.getLogger(log_type) 19 logger.setLevel(settings.LOG_LEVEL) 20 21 # 屏幕handler 22 ch = logging.StreamHandler() 23 ch.setLevel(settings.LOG_LEVEL) 24 25 # 文件handler 26 log_file = os.path.join(os.path.join(settings.BASE_DIR,"log"),settings.LOG_TYPES[log_type]) 27 fh = logging.FileHandler(log_file) 28 fh.setLevel(settings.LOG_LEVEL) 29 30 # handler輸出的格式設(shè)置 31 formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelno)s-%(message)s") 32 33 # 關(guān)聯(lián)handler和formatter 34 ch.setFormatter(formatter) 35 fh.setFormatter(formatter) 36 37 # 告訴logger輸出不同的handler 38 logger.addHandler(ch) 39 logger.addHandler(fh) 40 41 return logger 42 43 44 def show_logger(acc_id, log_obj, year_month): 45 ''' 46 47 :param acc_id: 48 :param log_obj: 49 :param year_month: 50 :return: 51 ''' 52 53 bill_bday, bill_eday = billdate.get_bill_date(year_month) 54 print(templates.STATEMENT_TEMP.format(acc_id, bill_bday, bill_eday)) 55 log_path = os.path.join(settings.LOG_DATABASE["database_path"], settings.LOG_TYPES[log_obj]) 56 with open(log_path,"r+", encoding="utf-8") as file: 57 for i in file: 58 log_time = datetime.datetime.strptime(i.split(",")[0], "%Y-%m-%d %H:%M:%S") 59 account_id = i.split("-")[5].split(":")[1] 60 if acc_id == account_id and bill_bday <= log_time < bill_eday: 61 print(i) 62 print("") core\logger 1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import os, sys, json 5 from prettytable import PrettyTable 6 from conf import settings 7 from conf import templates 8 from core import auth 9 from core import shopping 10 from core import logger 11 from core import transaction 12 from core import update_acc_info 13 14 15 TRANSACTION_LOGGER = logger.logger("transactions") 16 ACCESS_LOGGER = logger.logger("access") 17 18 # 登陸成功后,將信息更新入tmp USER_DATA 19 USER_DATA = { 20 "account_id": None, 21 "is_authenticated": False, # 在客戶進(jìn)行不同操作時,都需要驗證是否登陸 22 "account_data": None # json文件信息 23 } 24 25 def verify(func): 26 ''' 27 裝飾器,每次在客戶轉(zhuǎn)賬,還款,取現(xiàn)等現(xiàn)金操作時,驗證是已經(jīng)登陸。 28 :param func: 29 :return: 30 ''' 31 def wrapper(*args,**kwargs): 32 if USER_DATA["is_authenticated"]: 33 res = func(*args,**kwargs) 34 else: 35 print("please log in again!") 36 return wrapper 37 38 @verify 39 def shopping_menu(acc_data): 40 ''' 41 購物車 42 :param acc_data: 43 :return: 44 ''' 45 shopping.shopping(acc_data) 46 47 48 # 寫日志 49 def get_acc_info(acc_data): 50 ''' 51 client function 2: 獲取賬戶信息 52 :param acc_data: 53 :return: 54 ''' 55 print("2.account information") 56 table = PrettyTable(["Account Id", "Credit", "Current Balance", "Expired Date"]) 57 table.add_row( 58 [acc_data["id"], acc_data["credit"], acc_data["balance"], acc_data["expire_date"]]) 59 print(table) 60 client_portal() 61 62 63 @verify 64 def repayment(acc_data): 65 ''' 66 打印current balance, 并且還款 67 :param acc_data: 68 :return: 69 ''' 70 table = PrettyTable(["Account Id", "Credit", "Current Balance"]) 71 table.add_row([acc_data["id"],acc_data["credit"], acc_data["balance"]]) 72 print(table) 73 back_flag = False 74 while not back_flag: 75 repay_amount = input("\033[33;1mPlease input repay amount\033[0m or press [b] for back").strip() 76 if len(repay_amount) > 0 and repay_amount.isdigit(): 77 n_acc_data = transaction.transaction(acc_data, TRANSACTION_LOGGER, "repay", repay_amount) 78 new_balance = n_acc_data["balance"] 79 if new_balance: 80 print("Your credit card has been repaid. Current balance is %s" % acc_data["balance"]) 81 client_portal() 82 elif repay_amount == "b": 83 back_flag = True 84 else: 85 print("Please input a valid number") 86 back_flag = True 87 88 @verify 89 def withdrawal(acc_data): 90 ''' 91 取款 92 :param acc_data: 93 :return: 94 ''' 95 print("Current balance: %s" % acc_data["balance"]) 96 back_flag = False 97 while not back_flag: 98 withdraw_amount = input("\033[33;1mPlease input amount for withdrawal\033[0m or press [b] for back>>>").strip() 99 if len(withdraw_amount) > 0 and withdraw_amount.isdigit(): 100 n_acc_data= transaction.transaction(acc_data, TRANSACTION_LOGGER, "withdraw", withdraw_amount) 101 new_balance = n_acc_data["balance"] 102 print("You have withdrawn %s and your current balance is %s" %(withdraw_amount, new_balance)) 103 client_portal() 104 elif withdraw_amount == "b": 105 back_flag = True 106 else: 107 print("Please input a valid number") 108 back_flag = True 109 110 111 @verify 112 def transfer(acc_data): 113 ''' 114 轉(zhuǎn)賬 115 :param acc_data: 116 :return: 117 ''' 118 print("Current balance: %s" % acc_data["balance"]) 119 back_flag = False 120 while not back_flag: 121 transferee_acc_id = input('press [b] for back or please input transferee\'s account id:').strip() 122 transfer_amount = input("\033[33;1mPlease input amount for transfer(extra 5% transaction fee)\033[0m>>>").strip() 123 if len(transfer_amount) > 0 and transfer_amount.isdigit(): 124 transferee_acc_data = update_acc_info.load_account(transferee_acc_id) 125 transaction.transaction(acc_data, TRANSACTION_LOGGER, "transfer", transfer_amount) 126 transaction.transaction(transferee_acc_data,TRANSACTION_LOGGER,"receive", transfer_amount) 127 print("Successfully transferred. ") 128 client_portal() 129 elif transferee_acc_data == "b": 130 back_flag = True 131 else: 132 print("Please input a valid number") 133 continue 134 135 136 def statement(acc_data): 137 ''' 138 查詢賬單 139 :param acc_data: 140 :return: 141 ''' 142 143 back_flag = False 144 while not back_flag: 145 bill_month = input("Please input your desired year-month (e.g. 2001-02) or press [b] for back >>>").strip() 146 if len(bill_month) > 6: 147 acc_id = acc_data["id"] 148 logger.show_logger(acc_id, "transactions", bill_month) 149 elif bill_month == "b": 150 back_flag = True 151 else: 152 print("Please input a valid year and month") 153 back_flag 154 155 def logout(acc_id): 156 exit("Thank you for your trust to MyBank!") 157 158 159 def get_user_data(): 160 account_data = auth.login(USER_DATA, ACCESS_LOGGER) # 登陸驗證func 161 if account_data["status"] == 8: 162 exit("Please choose Admin portal!") 163 else: 164 USER_DATA["account_id"] = account_data["id"] 165 USER_DATA["account_data"] = account_data 166 USER_DATA["is_authenticated"] = True 167 return USER_DATA 168 169 170 def client_portal(): 171 ''' 172 客戶接口, 登陸后更新USER_DATA。 173 :return: 174 ''' 175 if USER_DATA["is_authenticated"] == False: 176 get_user_data() 177 account_data = USER_DATA["account_data"] 178 else: 179 account_data = USER_DATA["account_data"] 180 181 client_menu = { 182 "1": shopping_menu, 183 "2": get_acc_info, 184 "3": repayment, 185 "4": withdrawal, 186 "5": transfer, 187 "6": statement, 188 "7": logout 189 } 190 print(templates.CLIENT_WIN.format(USER_DATA["account_id"])) 191 exit_flag = False 192 while not exit_flag: 193 client_option = input("Please select your action >>>").strip() 194 if client_option in client_menu: 195 client_menu[client_option](account_data) 196 else: 197 print("Invalid option. please try again.") 198 exit_flag = True 199 200 201 def admin_create(): 202 ''' 203 管理員新創(chuàng)建賬戶 204 :return: 205 ''' 206 print(" -------------Admin to creat a new account--------------") 207 acc_id = input("New Account ID >>>").strip() 208 acc_psd = input("Initial passward >>>").strip() 209 acc_cc = str(input("New credit card # >>>").strip()) 210 acc_credit = input ("Initial credit >>>").strip() 211 enroll_date = str(input("Enroll date (e.g. 2000-01-01)>>>").strip()) 212 expire_date = str(input("Expired date (e.g. 2005-01-01) >>>").strip()) 213 account_dict = { 214 "id": acc_id, 215 "password": acc_psd, 216 "credit_card": acc_cc, 217 "credit": acc_credit, 218 "balance": 0, 219 "enroll_date": enroll_date, 220 "expire_date": expire_date, 221 "billing_day": 22, 222 "status": "0" # 0 = normal, 1 = locked, 2 = disabled, 8 = admin 223 } 224 acc_file = "%s.json" %acc_id 225 acc_path = os.path.join(settings.DATABASE["database_path"], acc_file) 226 with open(acc_path, "w", encoding="utf-8") as f: 227 json.dump(account_dict,f) 228 229 230 def admin_reactivate(): 231 """ 232 激活 233 :return: 234 """ 235 back_flag = False 236 while not back_flag: 237 acc_id = input("please input the account id you want to reactivate>>>") 238 acc_data = update_acc_info.load_account(acc_id) 239 reconfirm_msg = input("please reconfirm you want to reactivate the account (Y/N) or press [b] for back >>>").strip() 240 if reconfirm_msg == "Y": 241 acc_data["status"] = "0" 242 update_acc_info.dump_account(acc_data) 243 print("The account has been unlocked") 244 elif reconfirm_msg == "b": 245 back_flag = True 246 else: 247 print("Reactivation failed") 248 back_flag = True 249 250 251 def admin_freeze(): 252 ''' 253 凍結(jié) 254 :return: 255 ''' 256 back_flag = False 257 while not back_flag: 258 acc_id = input("please input the account id you want to freeze>>>") 259 acc_data = update_acc_info.load_account(acc_id) 260 reconfirm_msg = input("please reconfirm you want to freeze the account (Y/N) or press [b] for back>>>").strip() 261 if reconfirm_msg == "Y": 262 acc_data["status"] = "2" 263 update_acc_info.dump_account(acc_data) 264 elif reconfirm_msg == "b": 265 back_flag = False 266 else: 267 print("Freeze failed") 268 back_flag = True 269 270 271 def admin_credit_update(): 272 ''' 273 更新信用額度 274 :return: 275 ''' 276 back_flag = False 277 while not back_flag: 278 acc_id = input("please input the account id you want to update the credit >>>") 279 acc_data = update_acc_info.load_account(acc_id) 280 new_credit = input("please input the new credit for {}".format(acc_id)).strip() 281 if len(new_credit)> 0 and new_credit.isdigit(): 282 acc_data["credit"] = new_credit 283 update_acc_info.dump_account(acc_data) 284 else: 285 print("Invalid input") 286 back_flag = True 287 288 289 def admin_portal(): 290 ''' 291 管理員入口 292 :return: 293 ''' 294 account_data = auth.login(USER_DATA, ACCESS_LOGGER) 295 admin_menu = { 296 "1": admin_create, 297 "2": admin_reactivate, 298 "3": admin_freeze, 299 "4": admin_credit_update, 300 "5": exit 301 } 302 exit_flag = False 303 while not exit_flag: 304 if account_data["status"] == 8: 305 print(templates.ADMIN_WIN.format(account_data["id"])) 306 admin_option = input("Your action >>>").strip() 307 if admin_option in admin_menu: 308 admin_menu[admin_option]() 309 else: 310 print("Invalid option. please try again.") 311 continue 312 else: 313 exit("Permission denied") 314 315 316 def sys_run(): 317 ''' 318 主程序窗口 319 :return: 320 ''' 321 print(templates.OPEN_WIN) 322 open_input = input('\033[31;1mYour choice >>>\033[0m ') 323 open_dic = { 324 "1": admin_portal, 325 "2": client_portal 326 } 327 if open_input in open_dic: 328 open_dic[open_input]() 329 else: 330 print("Invalid option. please try again.") 331 332 333 sys_run() core\main #!usr/bin/env python # -*- coding:utf-8 -*-import sys import json from conf import templates from conf import settings from core import update_acc_info from core import maindef shopping(acc_data):# 購物acc_id = acc_data["id"]print(templates.SHOPPING_WIN.format(acc_id))menu_dict = settings.SHOPPING_MENUwhile True:for i in sorted(menu_dict):print(i)option1 = input('請選擇\033[001m產(chǎn)品分類\033[0m 【b】返回 【任意鍵】退出').strip() # 001加粗if option1 in menu_dict:print('{}清單如下:'.format(option1).rjust(25, '-'))for k in menu_dict[option1]:print(k, menu_dict[option1][k])while True:option2 = input('請選擇 \033[001m商品\033[0m 加入購物車【b】返回 【q鍵】退出 ').strip()if option2 in menu_dict[option1]:option3_num = input('請輸入購買數(shù)量').strip()if option3_num.isdigit() and int(option3_num) <= menu_dict[option1][option2]['數(shù)量']:num = int(option3_num)price = menu_dict[option1][option2]['單價']cost = num*pricebalance = acc_data["balance"]if cost <= balance:acc_data["balance"] = balance - costupdate_acc_info.dump_account(acc_data)menu_dict[option1][option2]['數(shù)量'] -= numprint("商品已購,您的最新余額為\033[34m%d\033[0m" % (acc_data["balance"]))breakelse:print('賬戶余額不足,請還款')main.client_portal()else:print("抱歉,商品數(shù)目不足")continueelif option2 == 'b':breakelif option2 == 'q':sys.exit()else:print('錯誤信息,請重新選擇')continueelif option1 == 'b':main.client_portal()else:sys.exit() core\shopping #!usr/bin/env python # -*- coding:utf-8 -*-from conf import settings from core import update_acc_infoTRANSACTION_TYPE = {'repay': {'action': 'plus', 'interest': 0}, # 還款'receive': {'action': "plus", 'interest': 0}, # 接收'withdraw': {'action': 'minus', 'interest':0.05}, # 提款'transfer': {'action': 'minus', 'interest':0.05}, # 轉(zhuǎn)出'pay': {'action': 'minus', 'interest': 0}, # 支付 }def transaction(acc_data, log_obj, tran_type, amount, **other):'''cover all money transactions listed in settings.TRANSACTION_TYPE:param acc_data::param log_obj::param tran_type::param amount::param other::return:'''amount = float(amount)transaction_type = settings.TRANSACTION_TYPEinterest = amount * transaction_type[tran_type]["interest"]if transaction_type[tran_type]["action"] == "plus":new_balance = acc_data["balance"] + amountelif transaction_type[tran_type]["action"] == "minus":new_balance = acc_data["balance"] - amount - interestif new_balance < 0:print('Your current balance is %s, which may not be enough for this transaction'% acc_data["balance"])acc_data["balance"] = new_balanceupdate_acc_info.dump_account(acc_data)log_obj.info("ID:{}-Action:{}-Amount:{}-Interest:{}".format(acc_data["id"],tran_type,amount,interest))return acc_data core\transaction 1 #!usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # function: update any modifies or transaction into json file 4 \ 5 6 import os 7 import json 8 from conf import settings 9 from core import db_handler 10 11 def dump_account(acc_data): 12 ''' 13 存入文件 14 :param acc_data: 15 :return: 16 ''' 17 acc_file = "%s.json" % acc_data["id"] 18 db_file_path = db_handler.db_handler(settings.DATABASE) 19 acc_path = os.path.join(db_file_path, acc_file) 20 #print(acc_path) 21 with open(acc_path,"w+", encoding="utf-8") as f: 22 json.dump(acc_data,f) 23 return True 24 25 26 def load_account(acc_id): 27 ''' 28 讀取文件,用于transfer 29 :param acc_id: 30 :return: 31 ''' 32 acc_file = "%s.json" % acc_id 33 db_file_path = db_handler.db_handler(settings.DATABASE) 34 acc_path = os.path.join(db_file_path, acc_file) 35 with open(acc_path, "r+", encoding="utf-8") as f: 36 acc_data = json.load(f) 37 return acc_data update_acc_info #!usr/bin/env python #-*- coding:utf-8 -*-import jsonaccount_dict = {"id": "admin001","password": "admin1","credit_card": None,"credit": None,"balance": None,"enroll_date": "2000-01-01","expire_date": "2999-12-31","billing_day": 22,"status": "8" # 0 = normal, 1 = locked, 2 = disabled, 8 = admin }account_file = "%s.json" % account_dict["id"]with open(account_file, "w+") as f:json.dump(account_dict,f) database\test_accounts_dumplog\access.log
log\transaction.log
?
示例
sample 1:? alex的列子
sample 2:大牛的例子(涉及類)
轉(zhuǎn)載于:https://www.cnblogs.com/lg100lg100/p/7527057.html
總結(jié)
以上是生活随笔為你收集整理的Python 基础 - Day 5 Assignment - ATM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个项目学会前端实现登录拦截
- 下一篇: Minutes和TotalMinutes