功能描述
作業需求:
1、額度 15000或自定義
2、實現購物商城,買東西加入購物車,呼叫信用卡介面結賬
3、可以提現,手續費5%
4、支援多賬戶登入
5、支援賬戶間轉賬
6、記錄每月日常消費流水
7、提供還款介面
8、ATM記錄操作日誌
9、提供管理介面,包括新增賬戶、使用者額度,凍結賬戶等。。。
10、使用者認證用裝飾器
注意:以上需求,要充分使用函式,請盡你的最大限度來減少重複程式碼!
流程圖
程式流程圖(待補全)
![]()
程式目錄結構
bin
├── atm.py # atm入口
├── __init__.py
└── manage.py # 管理入口
conf
├── __init__.py
└── settings.py # 配置檔案
core
├── accounts.py # 賬號新增、修改額度、禁用、啟動介面
├── actions.py # sql動作介面
├── auth.py # 使用者認證介面
├── database.py # 資料庫操作介面
├── db_handler.py# 無用到
├── __init__.py
├── logger.py # 日誌介面
├── main.py # 主介面
├── parsers.py # sql語法解析介面
└── transaction.py # 交易介面
db
├── accounts_table # 使用者賬號表
└── managers_table # 管理員賬號表
log
├── access.log #訪問日誌
└── transactions.log #交易日誌
程式主體
atm.py
#!_*_coding:utf-8_*_
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
from core import main
if __name__ == `__main__`:
main.run(`atm`)
manage.py
#!_*_coding:utf-8_*_
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
from core import main
if __name__ == `__main__`:
main.run(`manage`)
setting.py
#!_*_coding:utf-8_*_
#__author__:"Alex Li"
import os
import sys
import logging
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Database title summary
TITLE = [`id`,`name`,`age`,`phone`,`dept`,`enroll_date`,`expire_date`,`account`,`password`,`credit`,`balance`,`status`,`pay_day`]
# Account database setting
DATABASE = {
`engine`: `file_storage`, # support mysql, postgresql in the future
`name`:`accounts_table`,
`path`: "%s/db/" % BASE_DIR
}
# Manager account database setting
MANAGE_DATABASE = {
`engine`: `file_storage`, # support mysql, postgresql in the future
`name`:`managers_table`,
`path`: "%s/db/" % BASE_DIR
}
# logger setting
LOG_LEVEL = logging.INFO
LOG_TYPES = {
`transaction`: `transactions.log`,
`access`: `access.log`,
}
# Transaction setting
TRANSACTION_TYPE = {
`repay`:{`action`:`plus`, `interest`:0},
`withdraw`:{`action`:`minus`, `interest`:0.05},
`transfer`:{`action`:`minus`, `interest`:0.05},
`consume`:{`action`:`minus`, `interest`:0},
}
ACCOUNT_DEFAULT = {
`credit`: 15000.0
}
accounts.py
#!_*_coding:utf-8_*_
import json
import time
from core import database
from conf import settings
from core import parsers
from core import actions
def load_accounts(account):
""" Check account whether exists in a database
:param account:
:return:
"""
base_dir = settings.DATABASE[`path`]
sql_str = `select * from accounts_table where account = %s` % account
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
res = actions.actions(sql_type, dict_sql)
if not res:
return False
else:
return True
def change_account(account, set_str):
""" Change account data
:param account:
:param set_str:
:return:
"""
base_dir = settings.DATABASE[`path`]
sql_str = `update accounts_table set %s where account = %s` % (set_str, account)
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
actions.actions(sql_type, dict_sql)
def add_account(*args):
""" Add an new account
:param args:
:param kwargs:
:return:
"""
base_dir = settings.DATABASE[`path`]
sql_str = `add to accounts_table values %s` % (`,`.join(args))
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
actions.actions(sql_type, dict_sql)
actions.py
# -*- coding: utf-8 -*-
from core import database
from conf import settings
import re
def actions(sql_type,dict_sql):
""" sql操作主函式
:param sql_type: sql語句的型別
:return:
actions_dict[sql_type]
相應操作的函式
"""
actions_dict = {`select`: select_action,
`add`: add_action,
`del`: del_action,
`update`: update_action}
if sql_type in actions_dict: # 判斷匯入的sql型別是否在actions_dict字典中定義。
return actions_dict[sql_type](dict_sql)
else:
return False
def select_action(dict_sql):
temp_list = []
info = dict_sql[`select`]
data = database.read_db(dict_sql[`from`]) # 獲取原始資料庫檔案中的所有資料,data為列表格式
key = dict_sql[`where`][0] # 獲取sql語句中where語句的key值。如id = 1,獲取id
count = 0
for values in data: # 讀取data列表中的每一個元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = `"` + str(values[key]) + `"`
dict_sql[`where`][0] = value # 將values[key]的值取出並重新賦值為sql語句的key值。
print(where_action(dict_sql[`where`]))
if where_action(dict_sql[`where`]): # 將新的where語句,傳送給where_action語句進行bool判斷。
count += 1
temp_list.append(values)
return temp_list
def add_action(dict_sql):
""" 插入動作
獲取使用者輸入的values,並在表中插入
:param dict_sql: parsers函式處理後的字典格式的sql語句
"""
data = database.read_db(dict_sql[`to`]) # 獲取原始資料庫檔案中的所有資料
value = dict_sql[`values`] # 從dict_sql中獲取values的列表
t_id = str(int(data[-1][`id`]) + 1) # 獲取原始資料庫檔案中id列最後一行的id數值,並每次自動+1。然後轉換為字串格式
value.insert(0, t_id) # 將新增的id插入到value變數中
if len(value) != len(settings.TITLE): # 判斷輸入值得長度是否等於資料庫檔案中定義的列的長度
print(`列數不正確`)
else:
data.append(dict(zip(settings.TITLE, value))) # 在獲取的原始資料中插入行的資料
database.write_db(dict_sql[`to`], data)
def del_action(dict_sql):
""" 刪除動作函式
:param dict_sql: parsers函式處理後的字典格式的sql語句
"""
temp_list = []
data = database.read_db(dict_sql[`from`]) # 獲取原始資料庫檔案中的所有資料,data為列表格式
key = dict_sql[`where`][0] # 獲取sql語句中where語句的key值。如id = 1,獲取id
for values in data: # 讀取data列表中的每一個元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = `"` + str(values[key]) + `"`
dict_sql[`where`][0] = value # 將values[key]的值取出並重新賦值為sql語句的key值。
if where_action(dict_sql[`where`]): # 將新的where語句,傳送給where_action語句進行bool判斷。
temp_list.append(values) # 如果符合條件,就從data中移除對應的values
return temp_list
# print(`已刪除%s條記錄` % len(temp_list))
# for i in temp_list:
# data.remove(i)
# write_db(dict_sql[`from`], data) # 將新生成的data重新寫入檔案
def update_action(dict_sql):
""" 更新動作函式
:param dict_sql: parsers函式處理後的字典格式的sql語句
"""
data = database.read_db(dict_sql[`update`]) # 獲取原始資料庫檔案中的所有資料,data為列表格式
key = dict_sql[`where`][0] # 獲取sql語句中where語句的key值。如id = 1,獲取id
set_key = dict_sql[`set`][0] # 獲取set語句中使用者輸入的key
set_value = dict_sql[`set`][2].strip("`").strip(`"`) # 獲取set語句中使用者輸入的value
count = 0
for values in data: # 讀取data列表中的每一個元素,values是字典格式
if type(values[key]) is int:
value = str(values[key])
else:
value = `"` + str(values[key]) + `"`
dict_sql[`where`][0] = value # 將values[key]的值取出並重新賦值為sql語句的key值。
if where_action(dict_sql[`where`]): # 將新的where語句,傳送給where_action語句進行bool判斷。
count += 1
values[set_key] = set_value # 如果符合條件,使用將set_key的值修改為set_value
print(data)
print(`已更新%s條記錄` % count)
database.write_db(dict_sql[`update`], data) # 將新生成的data重新寫入檔案
def where_action(condition):
""" where語句操作函式
:param condition: 判斷語句。就是字典中where的值
:return:
"""
if `like` in condition: # 如果like在語句中
# 將where語句中的第二個引數和,第一個引數進行正則比較。如果執行正常就返回True
return re.search(condition[2].strip("`").strip(`"`), condition[0]) and True
else:
return eval(` `.join(condition)) # 除此使用eval進行python的邏輯判斷
auth.py
#!_*_coding:utf-8_*_
import os
from core import parsers
from core import actions
from core import db_handler
from conf import settings
from core import logger
import json
import time
def login_required(func):
"驗證使用者是否登入"
def wrapper(*args, **kwargs):
print(args, kwargs)
# print(`--wrapper--->`,args,kwargs)
if args[0].get(`is_authenticated`):
return func(*args, **kwargs)
else:
exit("User is not authenticated.")
return wrapper
def acc_auth(account, password, type):
```
優化版認證介面
:param account: credit account number
:param password: credit card password
:return: if passed the authentication , retun the account object, otherwise ,return None
```
# table = None
# base_dir = None
if type == `atm`:
base_dir = settings.DATABASE[`path`]
table = settings.DATABASE[`name`]
elif type == `manage`:
base_dir = settings.MANAGE_DATABASE[`path`]
table = settings.MANAGE_DATABASE[`name`]
sql_str = `select * from %s where account = %s` % (table, account)
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
print(dict_sql)
res = actions.actions(sql_type, dict_sql)
print(res)
if not res:
print(" 33[31;1mAccount ID and password is incorrect! 33[0m")
elif res[0][`password`] == password:
print(`haha`)
exp_time_stamp = time.mktime(time.strptime(res[0][`expire_date`], "%Y-%m-%d"))
if time.time() > exp_time_stamp:
print(" 33[31;1mAccount [%s] has expired,please contact the back to get a new card! 33[0m" % account)
elif res[0][`status`] == 1:
print(" 33[31;1mAccount [%s] has expired,please contact the back to get a new card! 33[0m" % account)
else: # passed the authentication
return res[0]
else:
print(" 33[31;1mAccount ID and password is incorrect! 33[0m")
def acc_login(user_data, log_obj, type):
```
account login func
:user_data: user info data , only saves in memory
:return:
```
retry_count = 0
while user_data[`is_authenticated`] is not True and retry_count < 3 :
account = input(" 33[32;1maccount: 33[0m").strip()
password = input(" 33[32;1mpassword: 33[0m").strip()
auth = acc_auth(account, password, type)
if auth: # not None means passed the authentication
log_obj.info("account [%s] login system" % account)
user_data[`is_authenticated`] = True
user_data[`account_id`] = account
return auth
retry_count +=1
else:
log_obj.error("account [%s] too many login attempts" % account)
exit()
def acc_logout(user_data, log_obj):
account = user_data[`account_data`][`name`]
user_data[`is_authenticated`] = False
log_obj.info("account [%s] logout system" % account)
exit("account [%s] logout system" % account)
databaase.py
# -*- coding: utf-8 -*-
from conf import settings
def read_db(table):
""" 讀取表檔案函式。
:param table: 表檔案引數
:return: 返回一個包含表檔案內容的字典
"""
title = settings.TITLE
try:
main_list = []
with open(table, `r`, encoding=`utf-8`) as rf:
for line in rf:
temp_list = []
if line.rstrip(`
`).split(`,`) == title:
continue
else:
for values in line.strip(`
`).split(`,`):
if values.isdigit():
temp_list.append(int(values))
else:
temp_list.append(values)
main_list.append(dict(zip(title, temp_list)))
return main_list
except FileNotFoundError as e:
print(e)
exit(1)
def write_db(table, data):
""" 寫入表檔案函式。
:param table: 表檔案引數
:param data: 匯入的資料。為字典格式
"""
value2 = `,`.join(settings.TITLE) + `
`
for values in data:
temp_list = []
for value in values.values():
temp_list.append(str(value))
value2 += `,`.join(temp_list) + `
`
with open(file=table, mode=`w`, encoding=`utf-8`) as wf:
wf.write(value2)
def print_info(info, **kwargs):
""" 列印函式。
用於select語句列印顯示
:param info: select語句中需要顯示的類
:param kwargs: 字典,用於進行操作的原始資料
:return:
"""
temp_list = []
if info == `*`:
for key in kwargs:
temp_list.append(str(kwargs[key]))
print(`,`.join(temp_list))
else:
info_list = info.split(`,`)
for i in info_list:
temp_list.append(str(kwargs[i]))
print(`,`.join(temp_list))
logger.py
#!_*_coding:utf-8_*_
"""
handle all the logging works
"""
import logging
from conf import settings
import time
import re
def logger(log_type):
# create logger
my_logger = logging.getLogger(log_type)
my_logger.setLevel(settings.LOG_LEVEL)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(settings.LOG_LEVEL)
# create file handler and set level to warning
log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOG_TYPES[log_type])
fh = logging.FileHandler(log_file)
fh.setLevel(settings.LOG_LEVEL)
# create formatter
formatter = logging.Formatter(`%(asctime)s - %(name)s - %(levelname)s - %(message)s`)
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
my_logger.addHandler(ch)
my_logger.addHandler(fh)
return my_logger
def get_log_info(account):
""" 將日誌的內容進行轉換後返回相應賬號的轉款資訊
:param account: 賬號引數
:return:
"""
temp_list = []
log_file = "%s/log/%s" % (settings.BASE_DIR, settings.LOG_TYPES[`transaction`])
with open(log_file, `r`) as f:
for i in f:
log_mat = re.search(`(d{4}-d{1,2}-d{1,2}sd{1,2}:d{1,2}:d{1,2}).*account:(.*?)s.*action:(.*?)s.*amount:(.*?)s.*interest:(.*)`,i)
datetime = time.strptime(log_mat.group(1),`%Y-%m-%d %H:%M:%S`)
account_id = log_mat.group(2)
action = log_mat.group(3)
amount = log_mat.group(4)
interest = log_mat.group(5)
if account_id == account:
temp_list.append([datetime,action,amount,interest])
return temp_list
main.py
#!_*_coding:utf-8_*_
""""
main program handle module , handle all the user interaction stuff
"""
from core import auth
from core import logger
from core import parsers
from core import transaction
from core.auth import login_required
from core import actions
from conf import settings
from core import accounts
import random
import datetime
import re
import time
# transaction logger
trans_logger = logger.logger(`transaction`)
# access logger
access_logger = logger.logger(`access`)
# temp account data ,only saves the data in memory
user_data = {
`account_id`: None,
`is_authenticated`: False,
`account_data`: None
}
@login_required
def account_info(acc_data):
""" print account Information
:param acc_data: account summary
:return:
"""
back_flag = False
info_temp_list = []
account_data = acc_data[`account_data`]
info_list = [`name`, `age`, `phone`, `enroll_date`, `expire_date`, `account`, `credit`, `balance`]
for i in info_list:
info_temp_list.append(str(account_data[i]))
info = ``` --------- BALANCE INFO --------
username : {0}
age: {1}
phone: {2}
enroll date: {3}
expire date: {4}
card number: {5}
credit: {6}
balance: {7}
```.format(*info_temp_list)
print(info)
while not back_flag:
input_b = input(" 33[33;1mInput `b` return to menu: 33[0m").strip()
if input_b == `b`:
back_flag = True
@login_required
def repay(acc_data):
"""
print current balance and let user repay the bill
:return:
"""
account_data = acc_data[`account_data`]
current_balance = ``` --------- BALANCE INFO --------
Credit : %s
Balance: %s```.format(account_data[`credit`], account_data[`balance`])
print(current_balance)
back_flag = False
while not back_flag:
repay_amount = input(" 33[33;1mInput repay amount: 33[0m").strip()
if len(repay_amount) > 0 and repay_amount.isdigit():
new_balance = transaction.make_transaction(trans_logger, account_data, `repay`, repay_amount)
if new_balance:
print(``` 33[42;1mNew Balance:%s 33[0m``` % (new_balance[`balance`]))
elif repay_amount == `b`:
back_flag = True
else:
print(` 33[31;1m[%s] is not a valid amount, only accept integer! 33[0m` % repay_amount)
@login_required
def withdraw(acc_data):
"""
print current balance and let user do the withdraw action
:param acc_data:
:return:
"""
account_data = acc_data[`account_data`]
current_balance = ``` --------- BALANCE INFO --------
Credit : %s
Balance: %s``` % (account_data[`credit`], account_data[`balance`])
print(current_balance)
back_flag = False
while not back_flag:
withdraw_amount = input(" 33[33;1mInput withdraw amount: 33[0m").strip()
if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
new_balance = transaction.make_transaction(trans_logger, account_data, `withdraw`, withdraw_amount)
if new_balance:
print(``` 33[42;1mNew Balance:%s 33[0m``` % (new_balance[`balance`]))
elif withdraw_amount == `b`:
back_flag = True
else:
print(` 33[31;1m[%s] is not a valid amount, only accept integer! 33[0m` % withdraw_amount)
@login_required
def transfer(acc_data):
""" transfer accounts
:param acc_data:
:return:
"""
account_data = acc_data[`account_data`]
current_balance = ``` --------- BALANCE INFO --------
Credit : %s
Balance: %s``` % (account_data[`credit`], account_data[`balance`])
print(current_balance)
back_flag = False
while not back_flag:
payee_account = input(" 33[33;1mInput payee account: 33[0m").strip()
if payee_account == `b`:
back_flag = True
else:
base_dir = settings.DATABASE[`path`]
sql_str = `select * from accounts_table where account = %s` % payee_account
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
res = actions.actions(sql_type, dict_sql)
if not res:
print(" 33[31;1mThe payee you entered is not a bank user! 33[0m")
else:
payee_account_data = res[0]
trans_amount = input(" 33[33;1mInput transfer amount: 33[0m").strip()
if len(trans_amount) > 0 and trans_amount.isdigit():
new_balance = transaction.make_transaction(trans_logger, account_data, `transfer`, trans_amount)
payee_balance = transaction.make_transaction(trans_logger, payee_account_data,
`repay`, trans_amount)
if new_balance:
print(``` 33[42;1mNew Balance:%s 33[0m``` % (new_balance[`balance`]))
if payee_balance:
print(``` 33[42;1mThe money has come to the payee [%s] 33[0m``` % payee_account)
elif trans_amount == `b`:
back_flag = True
else:
print(` 33[31;1m[%s] is not a valid amount, only accept integer! 33[0m` % trans_amount)
@login_required
def pay_check(acc_data):
""" Account pay check interface
:param acc_data:
:return:
"""
back_flag = False
account_id = acc_data[`account_id`]
local_month = time.localtime().tm_mon
res = logger.get_log_info(account_id)
if res:
for result in res:
if result[0].tm_mon == local_month:
pay_check_info = ``` --------- Datatime %s --------
Action: %s
Amount: %s
Interest: %s``` % (time.strftime(`%Y-%m-%d %H:%M:%S`,result[0]), result[1], result[2], result[3])
print(pay_check_info)
while not back_flag:
input_b = input(" 33[33;1mInput `b` return to menu: 33[0m").strip()
if input_b == `b`:
back_flag = True
@login_required
def logout(acc_data):
auth.acc_logout(acc_data, access_logger)
def interactive(acc_data):
""" Atm interactive main interface
:param acc_data: account summary
:return:
"""
menu = u```
------- Oldboy Bank ---------
33[32;1m1. 賬戶資訊(功能已實現)
2. 還款(功能已實現)
3. 取款(功能已實現)
4. 轉賬(功能已實現)
5. 賬單(功能已實現)
6. 退出(功能已實現)
33[0m```
menu_dic = {
`1`: account_info,
`2`: repay,
`3`: withdraw,
`4`: transfer,
`5`: pay_check,
`6`: logout,
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input(">>:").strip()
if user_option in menu_dic:
menu_dic[user_option](acc_data)
else:
print(" 33[31;1mOption does not exist! 33[0m")
@login_required
def add_account(acc_data):
exit_flag = False
# id, name, age, phone, dept, enroll_date, expire_date, account, password, credit, balance, status, pay_day
while not exit_flag:
account_name = input(" 33[33;1mInput user name: 33[0m").strip()
if len(account_name) > 0:
account_name = account_name
else:
continue
account_age = input(" 33[33;1mInput user age: 33[0m").strip()
if len(account_name) > 0 and account_age.isdigit():
account_age = account_age
else:
continue
account_phone = input(" 33[33;1mInput user phone number: 33[0m").strip()
if len(account_phone) > 0 and account_phone.isdigit() and len(account_phone) == 11:
account_phone = account_phone
else:
continue
account_dept = input(" 33[33;1mInput user dept: 33[0m").strip()
if len(account_dept) > 0:
account_dept = account_dept
else:
continue
account = ``.join(str(random.choice(range(10))) for _ in range(5)) # 隨機生成5位賬號
password = input(" 33[33;1mInput account password: 33[0m").strip()
if len(password) == 0:
password = `abcde`
else:
password = password
account_enroll_date = datetime.datetime.now().strftime("%Y-%m-%d") # 當前時間為開通時間
account_expire_date = (datetime.datetime.now() + datetime.timedelta(days=(3 * 365))).strftime("%Y-%m-%d") # 3年後為過期時間
#print(account_enroll_date,account_expire_date)
account_credit = input(" 33[33;1mInput account credit: 33[0m").strip()
if len(account_credit) == 0:
account_credit = str(settings.ACCOUNT_DEFAULT[`credit`])
else:
account_credit = account_credit
#print(account)
input_list = [account_name, account_age,account_phone,account_dept,account_enroll_date,account_expire_date,account,password,account_credit,account_credit,`0`,`22`]
print(input_list)
commit = input(" 33[33;1mCommit account or exit:(Y/N) 33[0m").strip().upper()
if commit == `Y`:
accounts.add_account(*input_list)
exit_flag = True
else:
exit_flag = True
@login_required
def change_credit(acc_data):
""" Change account credit amount
:param acc_data:
:return:
"""
exit_flag = False
while not exit_flag:
dis_account = input(" 33[33;1mInput account: 33[0m").strip()
if dis_account == `b`:
exit_flag = True
elif len(dis_account) > 0:
if accounts.load_accounts(dis_account):
new_credits = input(" 33[33;1mInput new credits amount: 33[0m").strip()
if len(new_credits) > 0 and new_credits.isdigit():
accounts.change_account(dis_account, `credit = %s` % new_credits)
else:
print(` 33[31;1m[%s] is not a valid amount, only accept integer! 33[0m` % new_credits)
else:
print(" 33[31;1mThe account you entered is not a bank user! 33[0m")
@login_required
def disable_account(acc_data):
""" Disable account
:return:
"""
exit_flag = False
while not exit_flag:
dis_account = input(" 33[33;1mInput account: 33[0m").strip()
if dis_account == `b`:
exit_flag = True
elif len(dis_account) > 0:
if accounts.load_accounts(dis_account):
accounts.change_account(dis_account, `status = 1`)
else:
print(" 33[31;1mThe account you entered is not a bank user! 33[0m")
@login_required
def enable_account(acc_data):
""" Enable account
:return:
"""
exit_flag = False
while not exit_flag:
dis_account = input(" 33[33;1mInput account: 33[0m").strip()
if dis_account == `b`:
exit_flag = True
elif len(dis_account) > 0:
if accounts.load_accounts(dis_account):
accounts.change_account(dis_account, `status = 0`)
else:
print(" 33[31;1mThe account you entered is not a bank user! 33[0m")
def mg_interactive(acc_data):
""" Mange interactive main interface
:param acc_data: 返回的使用者賬號的具體資訊
:return:
"""
menu = u```
------- Oldboy Bank ---------
33[32;1m1. 新增賬號(功能已實現)
2. 修改額度(功能已實現)
3. 禁用賬號(功能已實現)
4. 啟用賬號(功能已實現)
5. 退出(功能已實現)
33[0m```
menu_dic = {
`1`: add_account,
`2`: change_credit,
`3`: disable_account,
`4`: enable_account,
`5`: logout,
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input(">>:").strip()
if user_option in menu_dic:
menu_dic[user_option](acc_data)
else:
print(" 33[31;1mOption does not exist! 33[0m")
def run(type):
"""
this function will be called right a way when the program started, here handles the user interaction stuff
:return:
"""
if type == `atm`:
acc_data = auth.acc_login(user_data, access_logger, `atm`)
if user_data[`is_authenticated`]:
user_data[`account_data`] = acc_data
interactive(user_data)
elif type == `manage`:
acc_data = auth.acc_login(user_data, access_logger, `manage`)
if user_data[`is_authenticated`]:
user_data[`account_data`] = acc_data
mg_interactive(user_data)
parsers.py
# -*- coding: utf-8 -*-
import re
#from .help import help
def parsers(sql_str, sql_type, base_dir):
""" 語法解析函式
:param sql_type: 從main()函式匯入的sql語句型別。
:return:
parsers_dict[sql_type]
相應的語法解析函式
"""
parsers_dict = {`select`: select_parser,
`add`: add_parser,
`del`: del_parser,
`update`: update_parser}
if sql_type in parsers_dict:
return parsers_dict[sql_type](sql_str, sql_type, base_dir)
else:
return False
def select_parser(sql_str, sql_type, base_dir):
""" 搜尋語句解析函式
:param sql_str: 使用者輸入的sql語句
:param sql_type: 使用者輸入的sql語句型別
:param base_dir: 主函式匯入的資料庫所在路徑
:return:
"""
dict_sql = {} # 建立空字典
command_parse = re.search(r`selects(.*?)sfroms(.*?)swheres(.*)`, sql_str, re.I) # 使用正規表示式解析add語法,並且re.I忽略大小寫
if command_parse:
dict_sql[`select`] = command_parse.group(1)
dict_sql[`from`] = base_dir + command_parse.group(2) # sql字典`from’鍵新增資料庫表檔案路徑的值
dict_sql[`where`] = command_parse.group(3) # sql字典‘where’鍵新增插入的值
if logic_cal(dict_sql[`where`]): # 使用logic_cal函式將where語句語法再次進行解析
dict_sql[`where`] = logic_cal(dict_sql[`where`]) # 如解析有返回值,將返回值重新作為dict_sql[`where`]的值
return dict_sql
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
def add_parser(sql_str, sql_type, base_dir):
""" 新增語句解析函式
:param sql_str: 使用者輸入的sql語句
:param sql_type: 使用者輸入的sql語句型別
:param base_dir: 主函式匯入的資料庫所在路徑
:return:
dict_sql
解析後的字典格式sql語句
"""
dict_sql = {}
command_parse = re.search(r`addstos(.*?)svaluess(.*)`, sql_str, re.I) # 使用正規表示式解析add語法,並且re.I忽略大小寫
if command_parse:
dict_sql[`to`] = base_dir + command_parse.group(1) # sql字典`to’鍵新增資料庫表檔案路徑的值
dict_sql[`values`] = command_parse.group(2).split(`,`) # sql字典‘values’鍵新增插入的值
return dict_sql
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
def del_parser(sql_str, sql_type, base_dir):
""" 刪除語句解析函式
:param sql_str: 使用者輸入的sql語句
:param sql_type: 使用者輸入的sql語句型別
:param base_dir: 主函式匯入的資料庫所在路徑
:return:
dict_sql
解析後的字典格式sql語句
"""
dict_sql = {}
command_parse = re.search(r`delsfroms(.*?)swheres(.*)`, sql_str, re.I)
if command_parse:
dict_sql[`from`] = base_dir + command_parse.group(1) # sql字典`to’鍵新增資料庫表檔案路徑的值
dict_sql[`where`] = command_parse.group(2) # sql字典‘where’鍵新增插入的值
if logic_cal(dict_sql[`where`]): # 使用logic_cal函式將where語句語法再次進行解析
dict_sql[`where`] = logic_cal(dict_sql[`where`]) # 如解析有返回值,將返回值重新作為dict_sql[`where`]的值
return dict_sql
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
def update_parser(sql_str, sql_type, base_dir):
""" 更新語句解析函式
:param sql_str: 使用者輸入的sql語句
:param sql_type: 使用者輸入的sql語句型別
:param base_dir: 主函式匯入的資料庫所在路徑
:return:
dict_sql
解析後的字典格式sql語句
"""
dict_sql = {}
command_parse = re.search(r`updates(.*?)ssets(.*?)=(.*?)swheres(.*)`, sql_str, re.I)
if command_parse:
dict_sql[`update`] = base_dir + command_parse.group(1) # sql字典`to’鍵新增資料庫表檔案路徑的值
dict_sql[`set`] = [command_parse.group(2), `=`, command_parse.group(3)] # sql字典‘where’鍵新增插入的值
dict_sql[`where`] = command_parse.group(4)
if logic_cal(dict_sql[`where`]) and logic_cal(dict_sql[`set`]): # 如果where語句、set語句都符合logic_cal中定義的規範
dict_sql[`where`] = logic_cal(dict_sql[`where`]) # 如解析有返回值,將返回值重新作為dict_sql[`where`]的值
dict_sql[`set`] = logic_cal(dict_sql[`set`]) # 如解析有返回值,將返回值重新作為dict_sql[`set`]的值
return dict_sql
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
else:
print(help(sql_type)) # 當語法解析不正常答應幫助
def logic_cal(logic_exp):
""" 邏輯函式
:param logic_exp: sql語句中和邏輯判斷相關的語句,列表格式。如[‘age`,`>=`,20] 或 [‘dept`,`like`,`HR`]
:return:
logic_exp
經過語法解析後的邏輯判斷語句。列表格式。如[‘age`,`==`,20] 或 [‘dept`,`like`,`HR`]
"""
# 表示式列表優化成三個元素,形如[‘age`,`>=`,20] 或 [‘dept`,`like`,`HR`]
logic_exp = re.search(`(.+?)s([=<>]{1,2}|like)s(.+)`, ``.join(logic_exp))
if logic_exp:
logic_exp = list(logic_exp. group(1, 2, 3)) # 取得re匹配的所有值,並作為一個列表
if logic_exp[1] == `=`:
logic_exp[1] = `==`
# 判斷邏輯運算的比較符號後的值是否字母,並且使用者是否輸入了雙引號。如沒有輸入手工新增上雙引號。
if not logic_exp[2].isdigit() and not re.search(`"(.*?)"`, logic_exp[2]):
logic_exp[2] = `"` + logic_exp[2] + `"`
return logic_exp
else:
return False
transaction.py
#!_*_coding:utf-8_*_
from conf import settings
from core import accounts
from core import logger
from core import parsers
from core import actions
#transaction logger
def make_transaction(log_obj, account_data, tran_type, amount, **others):
```
deal all the user transactions
:param account_data: user account data
:param tran_type: transaction type
:param amount: transaction amount
:param others: mainly for logging usage
:return:
```
amount = float(amount)
if tran_type in settings.TRANSACTION_TYPE:
interest = amount * settings.TRANSACTION_TYPE[tran_type][`interest`]
old_balance = float(account_data[`balance`])
if settings.TRANSACTION_TYPE[tran_type][`action`] == `plus`:
new_balance = old_balance + amount + interest
elif settings.TRANSACTION_TYPE[tran_type][`action`] == `minus`:
new_balance = old_balance - amount - interest
#check credit
if new_balance <0:
print(``` 33[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is
[%s]``` %(account_data[`credit`],(amount + interest), old_balance ))
return
account_data[`balance`] = new_balance
base_dir = settings.DATABASE[`path`]
sql_str = `update accounts_table set balance = %s where account = %s` % (new_balance, account_data[`account`])
sql_type = sql_str.split()[0]
dict_sql = parsers.parsers(sql_str, sql_type, base_dir)
actions.actions(sql_type, dict_sql)
# accounts.dump_account(account_data) # save the new balance back to file
log_obj.info("account:%s action:%s amount:%s interest:%s" %
(account_data[`account`], tran_type, amount,interest) )
return account_data
else:
print(" 33[31;1mTransaction type [%s] is not exist! 33[0m" % tran_type)
啟動命令
啟動命令。
python atm.py
python manage.py
釋出資訊
- 作者:henryyuan
- 日期:2018/03/05
- 版本:Version 1.0
- 工具:PyCharm 2017.3.3
- 版本:Python 3.6.4
- MarkDown工具:pycharm
- 流程圖工具:ProcessOn
新聞
無
歷史記錄
2018-3-5 Version:1.0
遇到的問題:
1.) 在main.py介面中的add_account()函式。用於新增賬號。需要輸入多個input條件。程式碼如下:
account_name = input(" 33[33;1mInput user name: 33[0m").strip()
# 有點重複程式碼的感覺
if len(account_name) > 0:
account_name = account_name
else:
continue
account_age = input(" 33[33;1mInput user age: 33[0m").strip()
# 有點重複程式碼的感覺
if len(account_name) > 0 and account_age.isdigit():
account_age = account_age
else:
continue
account_phone = input(" 33[33;1mInput user phone number: 33[0m").strip()
# 有點重複程式碼的感覺
if len(account_phone) > 0 and account_phone.isdigit() and len(account_phone) == 11:
account_phone = account_phone
else:
continue
每個input語句都需要有if的判斷,但當有多個input輸入語句時,就會出現過多的重複的if程式碼。如何減少if語句的程式碼量。