學(xué)習(xí)python之路--Day4:ATM程序

需求

  • 額度 15000或自定義
  • 實(shí)現(xiàn)購(gòu)物商城,買東西加入 購(gòu)物車徘熔,調(diào)用信用卡接口結(jié)賬
  • 可以提現(xiàn),手續(xù)費(fèi)5%
  • 支持多賬戶登錄
  • 支持賬戶間轉(zhuǎn)賬
  • 記錄每月日常消費(fèi)流水
  • 提供還款接口
  • ATM記錄操作日志
  • 提供管理接口串结,包括添加賬戶、用戶額度饶套,凍結(jié)賬戶等。垒探。妓蛮。
  • 用戶認(rèn)證用裝飾器

需求分析

  1. 額度,初始化為15000圾叼,可以寫入一個(gè)文件里balance.txt
  2. 購(gòu)物車應(yīng)用蛤克,可以參考購(gòu)物車作業(yè),整個(gè)購(gòu)物車可以放到一個(gè)函數(shù)里夷蚊,需要調(diào)用信用卡接口构挤,就需要調(diào)用信用卡模塊了,購(gòu)物車腳本可以和信用卡的放在一起
  3. 提現(xiàn)惕鼓,余額扣除提現(xiàn)金額*(1 + 0.05) 扣除金額不得大于余額的一半筋现,提現(xiàn)完了之后扣除余額
  4. 多賬戶登陸,用戶名密碼寫入一個(gè)文件里箱歧,參考登陸接口作業(yè)
  5. 賬戶之間轉(zhuǎn)賬矾飞,用戶名對(duì)應(yīng)的余額 - 轉(zhuǎn)賬金額,轉(zhuǎn)賬賬戶名對(duì)應(yīng)的余額 + 轉(zhuǎn)賬金額
  6. 記錄流水呀邢,還需要寫一個(gè)流水文件洒沦,記錄消費(fèi)商品,金額价淌,前面還需要加時(shí)間
  7. 還款接口申眼,可以理解為向余額添加
  8. ATM操作記錄
  9. 參考購(gòu)物車作業(yè)里的manage.py
  10. 裝飾器,我理解應(yīng)該是不同的操作输钩,給需要密碼驗(yàn)證的,加上輸入密碼驗(yàn)證模塊仲智,就像真正的ATM那樣买乃,非重要的操作可以不需要密碼

進(jìn)一步思考:
balance和用戶密碼可以寫成字典形式,用pickle導(dǎo)入到文件钓辆,到時(shí)候在load出來剪验,方便處理,按用戶名前联,密碼功戚,余額的形式對(duì)應(yīng)起來,寫在一個(gè)文件里似嗤。

import pickle

info_dict={'root':{'userpasswd':'python','balance':10000},
        'test':{'userpasswd':'test','balance':10000}}

f=open('user.info','wb')
pickle.dump(info_dict,f)
f.close()

購(gòu)物車程序?qū)懺?code>shopplist.py里啸臀,功能有選擇商品,加入購(gòu)物車,確認(rèn)付款乘粒,到支付接口豌注,完成后返回信息。
支付接口寫在credit.py 灯萍,支付函數(shù)payment()轧铁,支付需要調(diào)用修改余額函數(shù)write_balance() 記錄賬單記錄函數(shù)consumer_logger()
提現(xiàn)接口也可以寫在credit.py里,提現(xiàn)函數(shù)withdraw()旦棉,提現(xiàn)需要調(diào)用修改余額函數(shù)write_balance()齿风,記錄操作記錄atm_logger()

賬戶間轉(zhuǎn)賬寫在credit.py里,轉(zhuǎn)賬函數(shù)transfer()绑洛,轉(zhuǎn)賬需要提供轉(zhuǎn)賬賬戶名救斑,轉(zhuǎn)賬金額,需要調(diào)用修改余額函數(shù)write_balance()诊笤,記錄操作記錄atm_logger()
還款接口也可以寫在credit.py里系谐,還款函數(shù)repay(),需要調(diào)用修改余額函數(shù)write_balance()讨跟,記錄操作記錄atm_logger()

結(jié)構(gòu):

我們先來確定程序的結(jié)構(gòu)
-atm
--\bin
---atm.py
---shopping.py
---manager.py
--\core
---各類程序模塊
--\logs
---atm.log
---cust.log

其中bin目錄為執(zhí)行入口目錄纪他,atm.py是ATM仿真程序的啟動(dòng)入口,shopping.py是購(gòu)物車程序的啟動(dòng)入口晾匠,manager.py是管理賬戶程序的啟動(dòng)入口
core目錄下主要放置各類程序模塊
logs目錄下主要放置操作流水記錄日志茶袒,atm.log是ATM操作記錄,cust.log是信用卡消費(fèi)記錄
setting目錄下主要放置配置文件

流程圖

我們先來確定atm的流程圖


atm

然后是購(gòu)物車的流程圖


shopping

最后是manager的流程圖


manager

實(shí)現(xiàn)


用戶數(shù)據(jù)存放

考慮之前用字典存放用戶賬戶名和密碼凉馆,這次多了一個(gè)balance薪寓,那就字典里增加一個(gè)key叫'balance',字典形式這樣的:
{'test': {'balance': 11000.0, 'passwd': 'test'}, 'root': {'balance': 9000.0, 'passwd': 'python'}}

用戶名對(duì)應(yīng)一個(gè)字典澜共,內(nèi)字典key是passwd和balance向叉,對(duì)應(yīng)用戶的密碼和余額,在實(shí)現(xiàn)程序之前嗦董,先創(chuàng)建這個(gè)user.info文件
我用pickle.dump方法把測(cè)試用戶寫入文件:

import pickle

info_dict={'root':{'passwd':'python','balance':10000},
    'test':{'passwd':'test','balance':10000}}

f=open('user.info','wb')
pickle.dump(info_dict,f)
f.close()

同樣的母谎,用pickle的方法,寫一個(gè)product.txt的文件京革,用來存放商品信息奇唤,商品有名稱和價(jià)格,參考之前的購(gòu)物車項(xiàng)目匹摇,我們做成列表類型咬扇。
product.txt的腳本可以跟之前寫user.info文件的腳本合并,做成一個(gè)初始化腳本:

import pickle

info_dict={'root':{'passwd':'python','balance':10000},
    'test':{'passwd':'test','balance':10000}}

f=open('user.info','wb')
pickle.dump(info_dict,f)
f.close()

pro_list=[['iphone', 6200], ['mac pro', 12000], ['bike', 800], ['book', 55], ['coffee', 31], ['windows pc', 4900]]
f=open('product.txt','wb')
pickle.dump(pro_list,f)
f.close()

初始化數(shù)據(jù)好了之后廊勃,已經(jīng)擁有了一些測(cè)試賬號(hào)和商品懈贺,開始做我們的登陸接口login

登陸接口

參考之前的作業(yè),登錄接口的主邏輯我們這樣寫:

f=open('user.info','rb')
    user_dict=pickle.load(f)
    f.close()
    
    while True:
        username=input('Enter your account:')
        password=input('Enter your password:')
        if username not in user_dict:
            print('Sorry,your account is not exist!\n')
            continue
       
        else:
            if user_dict[username]['passwd'] != password:
                print ('Sorry,your password invalid!\nPlease try again!\n')
                continue
            else:
                print ('Welcome {}!'.format(username))
                break

輸入帳號(hào)密碼,判斷是否存在用戶隅居,之后判斷密碼是否是字典里用戶名對(duì)應(yīng)的二級(jí)字典'passwd'對(duì)應(yīng)的value钠至,稍后這個(gè)需要做成裝飾器,我們先做成一個(gè)可調(diào)用的函數(shù)形式:

def login():
    f=open('user.info','rb')
    user_dict=pickle.load(f)
    f.close()
    
    
    while True:
        username=input('Enter your account:')
        password=input('Enter your password:')
        if username not in user_dict:
            print('Sorry,your account is not exist!\n')
            continue
       
        else:
            if user_dict[username]['passwd'] != password:
                print ('Sorry,your password invalid!\nPlease try again!\n')
                continue
            else:
                print ('Welcome {}!'.format(username))
                break
    return username

函數(shù)返回的值我們暫時(shí)定為輸入的用戶名胎源。

還有一個(gè)凍結(jié)賬戶的需求棉钧,這里還需要有個(gè)blacklist.txt用來存放被凍結(jié)的賬戶,參考之前的作業(yè)涕蚤,黑名單做成列表宪卿,存放用戶名,pickle序列化到文件里万栅。
在初始化腳本里加上創(chuàng)建blacklist.txt文件的代碼:

import pickle

info_dict={'root':{'passwd':'python','balance':10000},
    'test':{'passwd':'test','balance':10000}}

blacklist=['blacklist']

f=open('user.info','wb')
pickle.dump(info_dict,f)
f.close()

pro_list=[['iphone', 6200], ['mac pro', 12000], ['bike', 800], ['book', 55], ['coffee', 31], ['windows pc', 4900]]

f=open('product.txt','wb')
pickle.dump(pro_list,f)
f.close()

f=open('blacklist.txt','wb')
pickle.dump(blacklist,f)
f.close()

創(chuàng)建好之后佑钾,完善登錄接口的邏輯,我們把user.info文件寫成變量info_path烦粒,取得值是本文件所在目錄下的'user.info'休溶,黑名單文件同理也這么寫:

#owner:houyizhong
#version:1.0

import pickle
import os

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'
blackfile_path=dirname+os.sep+'blacklist.txt'

def login():
    f=open(info_path,'rb')
    user_dict=pickle.load(f)
    f.close()
    
    blackfile=open(blackfile_path,'rb')
    blacklist=pickle.load(blackfile)
    blackfile.close()

    while True:
        username=input('Enter your account:')
        password=input('Enter your password:')
        if username not in user_dict:
            print('Sorry,your account is not exist!\n')
            continue
        elif username in blacklist:
                    print ("Sorry you are in blacklist!")
                    continue
        else:
            if user_dict[username]['passwd'] != password:
                print ('Sorry,your password invalid!\nPlease try again!\n')
                continue
            else:
                print ('Welcome {}!'.format(username))
                break
    
    return username

新增邏輯對(duì)blacklist.txt的讀取列表,登錄接口里對(duì)用戶輸入的用戶名的判斷扰她,是否在列表里兽掰。

信用卡

登錄接口完成之后,我們?cè)賮硪灰粚?shí)現(xiàn)信用卡功能的各個(gè)模塊徒役。

我把信用卡功能分為消費(fèi)(即支付)孽尽,查余額,查賬單忧勿,轉(zhuǎn)賬杉女,提現(xiàn),還款等功能塊鸳吸。我們一個(gè)個(gè)來實(shí)現(xiàn)熏挎。

還記得我們的賬戶余額是寫在用戶信息的文件里,作為二級(jí)字典的value存在的嗎晌砾?消費(fèi)坎拐,轉(zhuǎn)賬,提現(xiàn)贡羔,還款都要對(duì)余額有個(gè)修改操作廉白,我們可以統(tǒng)一做成一個(gè)寫入余額的功能模塊个初。
實(shí)現(xiàn)寫入文件的模塊balance_module

import pickle
import os

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'

def write_balance(data):
    f=open(info_path,'wb')
    pickle.dump(data,f)
    f.close()

上面的代碼乖寒,我是打開相對(duì)路徑下的user.info文件,其實(shí)是跟balance_module是屬于同一目錄的院溺,寫成info_path可以方便日后遷移user.info路徑楣嘁。
函數(shù)write_balance接受的是一個(gè)字典,模塊會(huì)把這個(gè)字典寫入文件,覆蓋之前的內(nèi)容逐虚,這就要求我們傳入的字典是帶有所有用戶信息的聋溜,一個(gè)已經(jīng)調(diào)整好的字典,不會(huì)再有變動(dòng)了叭爱。
這樣寫的好處是撮躁,所有信息修改完成之后,才會(huì)寫入文件买雾,這樣下次讀取的文件內(nèi)容就是最新的了把曼。這個(gè)道理我們?cè)?a href="http://www.reibang.com/p/cce1e89d48ab" target="_blank">上一篇中已經(jīng)探討過。

讀取user.info文件的函數(shù)
info_path的路徑即為user.info的相對(duì)于credit.py的位置

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'

def read_info():

    f=open(info_path,'rb')
    data=pickle.load(f)
    f.close()
    return data

返回的data是提取出來的字典漓穿。

一些基本動(dòng)作

我們?cè)趯懗绦驎r(shí)嗤军,常常會(huì)遇到一些動(dòng)作是頻繁做的,比如扣除余額(消費(fèi)晃危,提現(xiàn)叙赚,轉(zhuǎn)賬都會(huì)用到),添加余額(還款僚饭,收到轉(zhuǎn)賬)震叮,還有判斷余額是否充足,是否滿足動(dòng)作(消費(fèi)浪慌,提現(xiàn))所需的金額冤荆。這些可以復(fù)用的代碼,我們就把它做成函數(shù),需要時(shí)調(diào)用好了。

def add(username,bill,data):
    balance=data[username]['balance']
    balance += bill
    data[username]['balance']=balance
    return data

def subtract(username,bill,data):
    balance=data[username]['balance']
    balance -= bill
    data[username]['balance']=balance
    print ('Your balance is {}\n'.format(balance))
    return data

def judgment(username,bill):
    data=read_info()
    balance=data[username]['balance']
    if balance >= bill:
        return 'success'
    else:
        print ('Your balance is not enought!\n')
        return 'failure'

余額的刪減都需要對(duì)整個(gè)字典進(jìn)行修改(這樣返回?cái)?shù)據(jù)時(shí)蜻展,接受數(shù)據(jù)的模塊處理更方便赁濒,直接把data寫入文件),判斷余額是否滿足動(dòng)作所需金額bill的函數(shù)袋马,我們返回是'success'和'failure',這樣調(diào)用函數(shù)的模塊更容易判斷是否滿足,直接根據(jù)收到的字符來判斷损话。

日志記錄
我們要有日志記錄功能,記錄我們每一次的消費(fèi)槽唾,要有消費(fèi)時(shí)間丧枪,消費(fèi)項(xiàng)目,金額庞萍,消費(fèi)記錄這個(gè)動(dòng)作做成模塊拧烦,其他模塊可以復(fù)用:

def consumer_logger(username,stock,price):

    user_dir=log_path+os.sep+username

    if not os.path.exists(user_dir):
        os.mkdir(user_dir)

    cust_log=user_dir+os.sep+'cust.log'

    times=time.strftime('%Y%m%d%H%M%S')
    data='{0}\t{1}\t{2}'.format(times,stock,price)

    log=open(cust_log,'a')
    log.write('{}\n'.format(data))
    log.close()

我們的日志是放在logs目錄下的,同時(shí)還要根據(jù)用戶不同創(chuàng)建不同的日志信息钝计,這樣方便區(qū)分恋博。
我們用user_dir代表logs下的用戶文件夾齐佳,當(dāng)不存在時(shí),創(chuàng)建文件夾
cust_log代表用戶文件夾下的cust.log文件债沮,具體的信息盛放在里面炼吴。
接受的形參分別代表用戶名,商品名(購(gòu)物車列表)疫衩,金額
調(diào)用time模塊硅蹦,用time.strftime()方法取到年月日小時(shí)分秒級(jí)別的時(shí)間,用制表符寫入文件

同理闷煤,atm操作記錄也這么寫

def atm_logger(username,operating,money):
    user_dir=log_path+os.sep+username

    if not os.path.exists(user_dir):
        os.mkdir(user_dir)

    atm_log=user_dir+os.sep+'atm.log'

    times=time.strftime('%Y%m%d%H%M%S')
    data='{0}\t{1}\t{2}'.format(times,operating,money)

    log=open(atm_log,'a')
    log.write('{}\n'.format(data))
    log.close()

接受的形參分別為用戶名提针,動(dòng)作,金額曹傀。

支付模塊

我們寫一個(gè)支付函數(shù)payment來實(shí)現(xiàn)邏輯:

import balance_module

def payment(shoplist,bill):

    data=read_info()
    username=login()

    result=judgment(username,bill)

    if result == 'success':
        data=subtract(username,bill,data)
        balance_module.write_balance(data)
        consumer_logger(username,shoplist,bill)

    return result

可以看到我們需要調(diào)用用戶認(rèn)證接口辐脖,因?yàn)榈礁犊罱缑媪耍仨氈楞y行賬戶皆愉。
調(diào)用了讀取用戶信息字典的read_info()函數(shù)嗜价,將字典提取出來
調(diào)用了judgment()來判斷用戶對(duì)應(yīng)的余額是否滿足
如果收到的是'success',調(diào)用扣除余額的函數(shù)幕庐,將字典寫入文件的函數(shù)久锥,消費(fèi)日志記錄函數(shù)

以上函數(shù)我們都已經(jīng)寫出來了。
然后函數(shù)返回的結(jié)果是成功或者失敗异剥。很容易理解對(duì)吧瑟由。

轉(zhuǎn)賬模塊就是一個(gè)用戶余額減少,另一個(gè)用戶余額增加冤寿,可以這么寫(為了直觀歹苦,我沒有把add() subtract() judgment() atm_logger()這些調(diào)用的函數(shù)寫出來,下面幾個(gè)也是如此):

import balance_module

def transfer():
    username=login()
    
    data=read_info()
    transfer_account=input('Enter transfer account:')
    transfer_money=input('Enter transfer money:')
    if transfer_account in data:
        if transfer_money.isdigit:
            transfer_money=float(transfer_money)
            result=judgment(username,transfer_money)
            if result == 'success':
                data=subtract(username,transfer_money,data)
                data=add(transfer_account,transfer_money,data)
                print ('Your transfer done!\n')
                balance_module.write_balance(data)
                atm_logger(username,'transfer',transfer_money)
            elif result == 'failure':
                print ('Your balance is not enought!\n')
            else:
                print ('Sorry,there have some unknown error!\n')
        else:
            print ('Sorry,your enter money is not a digit!\n')
    else:
        print('Sorry,your enter account is not exist!\n')

提現(xiàn)模塊也很好寫督怜,用戶余額減少殴瘦,同時(shí)判斷余額一半是否大于提現(xiàn)的金額:

import balance_module

def withdraw():
    username=login()
    data=read_info()
    withdraw_money=input('Enter your withdraw money:')
    if withdraw_money.isdigit():
        cost_money=float(withdraw_money)*(1+0.05)
        result=judgment(username,cost_money)
        withdraw_money=float(withdraw_money)
        if result == 'success':
            if withdraw_money > (data[username]['balance']/2):
                print ('Sorry,your withdraw money is more than avalid balance!\n')
            else:
                data=subtract(username,cost_money,data)
                balance_module.write_balance(data)
                atm_logger(username,'withdraw',cost_money)
                print ('Your withdraw done!\n')
    else:
        print('Sorry,you enter is not digit!\n')

也是調(diào)用了一堆現(xiàn)成的函數(shù),把它們拼貼起來号杠。

還款蚪腋,就是新增余額:

import balance_module

def repay():
    username=login()
    data=read_info()
    repay_money=input('Enter your repay money:')
    if repay_money.isdigit():
        repay_money=float(repay_money)
        data=add(username,repay_money,data)
        balance_module.write_balance(data)
        atm_logger(username,'repay',repay_money)
        print('Your repay done!\n')
    else:
        print('Sorry,your enter is not digit!\n')

以上幾個(gè)函數(shù)基本實(shí)現(xiàn)了一個(gè)信用卡的基本功能

完整的代碼

#owner:houyizhong
#version:1.0

import pickle,time,os
import  balance_module
from demo_login import login

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'
log_path=os.path.dirname(dirname)+os.sep+'logs'

def read_info():
    f=open(info_path,'rb')
    data=pickle.load(f)
    f.close()
    return data

def add(username,bill,data):
    balance=data[username]['balance']
    balance += bill
    data[username]['balance']=balance
    return data

def subtract(username,bill,data):
    balance=data[username]['balance']
    balance -= bill
    data[username]['balance']=balance
    print ('Your balance is {}\n'.format(balance))
    return data

def judgment(username,bill):
    data=read_info()
    balance=data[username]['balance']
    if balance >= bill:
        return 'success'
    else:
        print ('Your balance is not enought!\n')
        return 'failure'

def atm_logger(username,operating,money):
    user_dir=log_path+os.sep+username
    if not os.path.exists(user_dir):
        os.mkdir(user_dir)
    atm_log=user_dir+os.sep+'atm.log'
    times=time.strftime('%Y%m%d%H%M%S')
    data='{0}\t{1}\t{2}'.format(times,operating,money)
    log=open(atm_log,'a')
    log.write('{}\n'.format(data))
    log.close()

def consumer_logger(username,stock,price):
    user_dir=log_path+os.sep+username
    if not os.path.exists(user_dir):
        os.mkdir(user_dir)
    cust_log=user_dir+os.sep+'cust.log'
    times=time.strftime('%Y%m%d%H%M%S')
    data='{0}\t{1}\t{2}'.format(times,stock,price)
    log=open(cust_log,'a')
    log.write('{}\n'.format(data))
    log.close()

def inquire():
    
    data=read_info()
    username=login()
    
    print('Your balance is :')
    print(data[username]['balance'])

def payment(shoplist,bill):
    data=read_info()
    username=login()
    result=judgment(username,bill)
    if result == 'success':
        data=subtract(username,bill,data)
        balance_module.write_balance(data)
        consumer_logger(username,shoplist,bill)
    return result

def transfer():
    username=login()
    
    data=read_info()
    transfer_account=input('Enter transfer account:')
    transfer_money=input('Enter transfer money:')
    if transfer_account in data:
        if transfer_money.isdigit:
            transfer_money=float(transfer_money)
            result=judgment(username,transfer_money)
            if result == 'success':
                data=subtract(username,transfer_money,data)
                data=add(transfer_account,transfer_money,data)
                print ('Your transfer done!\n')
                balance_module.write_balance(data)
                atm_logger(username,'transfer',transfer_money)
            elif result == 'failure':
                print ('Your balance is not enought!\n')
            else:
                print ('Sorry,there have some unknown error!\n')
        else:
            print ('Sorry,your enter money is not a digit!\n')
    else:
        print('Sorry,your enter account is not exist!\n')

def withdraw():
    username=login()
    data=read_info()
    withdraw_money=input('Enter your withdraw money:')
    if withdraw_money.isdigit():
        cost_money=float(withdraw_money)*(1+0.05)
        result=judgment(username,cost_money)
        withdraw_money=float(withdraw_money)
        if result == 'success':
            if withdraw_money > (data[username]['balance']/2):
                print ('Sorry,your withdraw money is more than avalid balance!\n')
            else:
                data=subtract(username,cost_money,data)
                balance_module.write_balance(data)
                atm_logger(username,'withdraw',cost_money)
                print ('Your withdraw done!\n')
    else:
        print('Sorry,you enter is not digit!\n')

def repay():
    username=login()
    data=read_info()
    repay_money=input('Enter your repay money:')
    if repay_money.isdigit():
        repay_money=float(repay_money)
        data=add(username,repay_money,data)
        balance_module.write_balance(data)
        atm_logger(username,'repay',repay_money)
        print('Your repay done!\n')
    else:
        print('Sorry,your enter is not digit!\n')

單獨(dú)測(cè)試每個(gè)模塊也是沒問題的。這樣 我們就可以繼續(xù)寫下去了姨蟋。

購(gòu)物車程序

這里可以參考之前的作業(yè)屉凯,再加上一個(gè)調(diào)用信用卡模塊

import pickle,os
import demo_credit
filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
product_path=dirname+os.sep+'product.txt'
def shopping():
    
    shopping_list=[]
    price=0
    
    '''read product'''
    f=open(product_path,'rb')
    product_list=pickle.load(f)
    f.close()
    def credit_payment(shoplist,price):
            result=demo_credit.payment(shoplist,price)
            
            if result == 'success':
                print ('You shopping done!')
            elif result == 'failure':
                print ('Sorry,your credit card balance is not enought!\n')
            else:
                print('Sorry,there have some unknown error!\n')

    while True:
        for index,item in enumerate(product_list):
            print(index+1,item)
        user_choice=input("Choice a product code('q' is exit.'pay' is settlement):")
        if user_choice.isdigit():
            user_choice = int(user_choice)
            if  user_choice <= len(product_list) and user_choice > 0:
                user_choice -= 1
                price += int(product_list[user_choice][1])
                shopping_list.append(product_list[user_choice][0])
                print ('Add {} to your shopplist!\n'.format(product_list[user_choice][0]))
            else:
                print("Sorry,product code isn's exist!\n")
        elif user_choice == "q":
            break
        elif user_choice == 'pay':
            print('Your check is {}'.format(price))
            if price != 0:
                credit_payment(shopping_list,price)
            break
        else:
            print("Your enter invalid!\n")

我們先進(jìn)入while循環(huán),打印商品列表眼溶,讓用戶輸入選擇悠砚,加入購(gòu)物車列表,q是退出偷仿,pay是支付哩簿,當(dāng)金額是0時(shí)不需要調(diào)用信用卡模塊。
支付大于0時(shí)調(diào)用信用卡模塊酝静,進(jìn)入支付接口节榜,從支付接口那里收到'success'或者'failure'的判斷,做成相應(yīng)動(dòng)作别智。

然后是管理模塊
也是參考之前的作業(yè)宗苍,調(diào)用現(xiàn)成的函數(shù),就完成了

import pickle,os
import balance_module
filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'
blackfile_path=dirname+os.sep+'blacklist.txt'
def read_info():
    f=open(info_path,'rb')
    data=pickle.load(f)
    f.close()
    return data
def add_account():
    data=read_info()
    count_name=input('Enter add account("b" is back):')
    if count_name == 'b':
        pass
    else:
        count_balance=input('Enter account balance("b" is back):')
        if count_balance.isdigit():
            count_balance=int(count_balance)
            count_passwd=input('Enter account password("b" is back):')
            if count_passwd == 'b':
                pass
            else:
                data[count_name]={'passwd':count_passwd,'balance':count_balance}
                balance_module.write_balance(data)
                print('Done')
        elif count_balance == 'b':
            pass
        else:
            print('Sorry,your enter balance is not digit!\n')
def change_account():
    data=read_info()
    change_name=input('Enter change account name:')
    if change_name in data:
        change_balance=input('Enter change account balance:')
        if change_balance.isdigit():
            change_balance=int(change_balance)
            data[change_name]['balance']=change_balance
            balance_module.write_balance(data)
            print ('Done')
        elif change_balance == 'b':
            pass
        else:
            print('Sorry,your enter is not digit!\n')
    elif change_name == 'b':
        pass
    else:
        print ('Sorry,your choose account is not exist!\n')
    
def blacklist():
    f=open(blackfile_path,'rb')
    list=pickle.load(f)
    f.close()
    data=read_info()
    blacklist_name=input('Enter blacklist account name:')
    if blacklist_name in data:
        list.append(blacklist_name)
        f=open(blackfile_path,'wb')
        pickle.dump(list)
        f.close()
    elif blacklist_name == 'b':
        pass
    else:
        print ('Sorry,you choose account is not exist!\n')

完成這些之后薄榛,我們來到bin目錄下實(shí)現(xiàn)啟動(dòng)接口

購(gòu)物車接口

這邊只是需要調(diào)用購(gòu)物車模塊讳窟,只是需要注意現(xiàn)在購(gòu)物車程序跟核心模塊不在一個(gè)目錄里,注意調(diào)用模塊時(shí)的路徑

import os,sys
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CORE_DIR=BASE_DIR+os.sep+'core'
sys.path.append(BASE_DIR)
sys.path.append(CORE_DIR)
import core
core.demo_shoplist.shopping()

把core目錄放進(jìn)系統(tǒng)變量敞恋,調(diào)用下面的模塊文件

管理程序

import os,sys
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CORE_DIR=BASE_DIR+os.sep+'core'
sys.path.append(BASE_DIR)
sys.path.append(CORE_DIR)
from core import demo_manage
action_list=['Add account','Edit account','Block account']
while True:
    for index,item in enumerate(action_list):
        print(index+1,item)
    print('"q" is exit.')
    enter_action=input('Enter your choice:')
    if enter_action.isdigit():
        if enter_action == '1':
            demo_manage.add_account()
            continue
        elif enter_action == '2':
            demo_manage.change_account()
            continue
        elif enter_action == '3':
            demo_manage.blacklist()
            continue
    else:
        if enter_action == 'q':
            exit()
        else:
            print('Sorry,your enter invaild!\n')

也是要把core目錄放進(jìn)系統(tǒng)變量里丽啡。

atm啟動(dòng)接口

import os
import sys
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CORE_DIR=BASE_DIR+os.sep+'core'
sys.path.append(BASE_DIR)
sys.path.append(CORE_DIR)
from core import demo_credit

action_list=['Query check','Transfer','Query balance','Withdraw','Repay']
while True:
    for index,item in enumerate(action_list):
        print(index+1,item)
    print('"q" is exit.')
    enter_action=input('Enter your choice:')
    if enter_action.isdigit():
        if enter_action == '1':
            '''Query check'''
            continue
        elif enter_action == '2':
            '''Transfer'''
            demo_credit.transfer()
            continue
        elif enter_action == '3':
            '''Query balance'''
            demo_credit.inquire()
            continue
        elif enter_action == '4':
            '''Withdraw'''
            demo_credit.withdraw()
            continue
        elif enter_action == '5':
            '''Repay'''
            demo_credit.repay()
            continue
        else:
            print ('Sorry,you enter invaild!\n')
            continue
    else:
        if enter_action == 'q':
            exit()
        else:
            print('Sorry,your enter invaild!\n')

主要是打印可操作項(xiàng),對(duì)輸入做判斷硬猫,調(diào)用響應(yīng)的模塊补箍,也是需要注意模塊調(diào)用時(shí)的添加系統(tǒng)變量。

用戶認(rèn)證用裝飾器

裝飾器的樣式這樣:

def login(func):
    def decorator(*args,**kwargs):
        
        func(*args,**kwargs)
        
    return decorator

@login
def func():
    pass

func()

我們對(duì)login()函數(shù)進(jìn)行改造

import pickle
import os
filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'
blackfile_path=dirname+os.sep+'blacklist.txt'
def login(func):
    def decorator(*args,**kwargs):
        f=open(info_path,'rb')
        user_dict=pickle.load(f)
        f.close()
        
        blackfile=open(blackfile_path,'rb')
        blacklist=pickle.load(blackfile)
        blackfile.close()
        while True:
            username=input('Enter your account:')
            password=input('Enter your password:')
            if username not in user_dict:
                print('Sorry,your account is not exist!\n')
                continue
            elif username in blacklist:
                print ("Sorry you are in blacklist!")
                continue
            else:
                if user_dict[username]['passwd'] != password:
                    print ('Sorry,your password invalid!\nPlease try again!\n')
                    continue
                else:
                    print ('Welcome {}!'.format(username))
                    break
        func(username,*agrs,**kwargs)
        
    return decorator

@login
def func(username):
    print(username)
func()

這樣測(cè)試啸蜜,可以正常實(shí)現(xiàn)功能坑雅,現(xiàn)在要融入其他模塊中。
在同級(jí)目錄下寫一個(gè)測(cè)試文件

from demo_login import login
@login
def func(username):
    print(username)
func()

測(cè)試衬横,可以實(shí)現(xiàn)裹粤,于是移植到其他模塊里。

import pickle,time,os
import  balance_module
from demo_login import login

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
info_path=dirname+os.sep+'user.info'
log_path=os.path.dirname(dirname)+os.sep+'logs'

@login
def query(username):
    user_dir=log_path+os.sep+username
    if not os.path.exists(user_dir):
        print('Sorry,you do not have check.')
    else:
        cust_log=user_dir+os.sep+'cust.log'
        if os.path.exists(cust_log):
            log=open(cust_log,'r')
            print('You check is:')
            print(log.read())
            log.close()
        else:
            print('Sorry,you do not have check.')
    
@login
def inquire(username):
    
    data=read_info()
    
    print('Your balance is :')
    print(data[username]['balance'])

@login
def payment(username,shoplist,bill):
    data=read_info()
    result=judgment(username,bill)
    if result == 'success':
        data=subtract(username,bill,data)
        balance_module.write_balance(data)
        consumer_logger(username,shoplist,bill)
    return result

@login
def transfer(username):
    data=read_info()
    transfer_account=input('Enter transfer account:')
    transfer_money=input('Enter transfer money:')
    if transfer_account in data:
        if transfer_money.isdigit:
            transfer_money=float(transfer_money)
            result=judgment(username,transfer_money)
            if result == 'success':
                data=subtract(username,transfer_money,data)
                data=add(transfer_account,transfer_money,data)
                print ('Your transfer done!\n')
                balance_module.write_balance(data)
                atm_logger(username,'transfer',transfer_money)
            elif result == 'failure':
                print ('Your balance is not enought!\n')
            else:
                print ('Sorry,there have some unknown error!\n')
        else:
            print ('Sorry,your enter money is not a digit!\n')
    else:
        print('Sorry,your enter account is not exist!\n')

@login
def withdraw(username):
    data=read_info()
    withdraw_money=input('Enter your withdraw money:')
    if withdraw_money.isdigit():
        cost_money=float(withdraw_money)*(1+0.05)
        result=judgment(username,cost_money)
        withdraw_money=float(withdraw_money)
        if result == 'success':
            if withdraw_money > (data[username]['balance']/2):
                print ('Sorry,your withdraw money is more than avalid balance!\n')
            else:
                data=subtract(username,cost_money,data)
                balance_module.write_balance(data)
                atm_logger(username,'withdraw',cost_money)
                print ('Your withdraw done!\n')
    else:
        print('Soory,you enter is not digit!\n')

@login
def repay(username):
    data=read_info()
    repay_money=input('Enter your repay money:')
    if repay_money.isdigit():
        repay_money=float(repay_money)
        data=add(username,repay_money,data)
        balance_module.write_balance(data)
        atm_logger(username,'repay',repay_money)
        print('Your repay done!\n')
    else:
        print('Sorry,your enter is not digit!\n')

測(cè)試可以實(shí)現(xiàn)功能

注意不止credit.py需要用到認(rèn)證蜂林,其他文件可能也需要遥诉,像是shoplist.py。代碼如下:

import pickle,os
from demo_login import login
import demo_credit

filename=os.path.abspath(__file__)
dirname=os.path.dirname(filename)
product_path=dirname+os.sep+'product.txt'

def shopping():
    
    shopping_list=[]
    price=0
    
    '''read product'''
    f=open(product_path,'rb')
    product_list=pickle.load(f)
    f.close()

    @login
    def credit_payment(username,shoplist,price):
            result=demo_credit.payment(username,shoplist,price)
            
            if result == 'success':
                print ('You shopping done!')
            elif result == 'failure':
                print ('Sorry,your credit card balance is not enought!\n')
            else:
                print('Sorry,there have some unknown error!\n')

    while True:
        for index,item in enumerate(product_list):
            print(index+1,item)
        user_choice=input("Choice a product code('q' is exit.'pay' is settlement):")
        if user_choice.isdigit():
            user_choice = int(user_choice)
            if  user_choice <= len(product_list) and user_choice > 0:
                user_choice -= 1
                price += int(product_list[user_choice][1])
                shopping_list.append(product_list[user_choice][0])
                print ('Add {} to your shopplist!\n'.format(product_list[user_choice][0]))
            else:
                print("Sorry,product code isn's exist!\n")
        elif user_choice == "q":
            break
        elif user_choice == 'pay':
            print('Your check is {}'.format(price))
            if price != 0:
                credit_payment(shopping_list,price)
            break
        else:
            print("Your enter invalid!\n")

這里用了之后噪叙,credit.py里的paymant()函數(shù)就可以去掉裝飾器了突那。

坑:

  • 所有用的文件都需要寫成變量形式啊,因?yàn)閱?dòng)入口目錄下面沒有啊构眯,而且不能寫死愕难,必須用os.path.dirname方式加os.sep加文件名拼貼才行啊1拱浴猫缭!
  • credit里的consumer_logger()函數(shù)需要按不同賬戶創(chuàng)建不同的log啊啊啊壹店!
  • 自己寫的模塊A import了另一個(gè)自己寫的模塊B猜丹,啟動(dòng)程序那里還需要加上模塊B所在路徑的系統(tǒng)搜索路徑啊~不然from package import 模塊A的時(shí)候,模塊A再import 模塊B硅卢,這個(gè)時(shí)候不知道從哪里找模塊B射窒,因?yàn)閱?dòng)程序的系統(tǒng)路徑里找不到模塊B藏杖;如果是import package,運(yùn)行__init__.py的時(shí)候脉顿,from . import 模塊B蝌麸,這個(gè)時(shí)候啟動(dòng)程序的系統(tǒng)搜索路徑里也找不到B。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艾疟,一起剝皮案震驚了整個(gè)濱河市来吩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔽莱,老刑警劉巖弟疆,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盗冷,居然都是意外死亡怠苔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門仪糖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘀略,“玉大人,你說我怎么就攤上這事乓诽≈难颍” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵鸠天,是天一觀的道長(zhǎng)讼育。 經(jīng)常有香客問我,道長(zhǎng)稠集,這世上最難降的妖魔是什么奶段? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮剥纷,結(jié)果婚禮上痹籍,老公的妹妹穿的比我還像新娘。我一直安慰自己晦鞋,他們只是感情好蹲缠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悠垛,像睡著了一般线定。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上确买,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天斤讥,我揣著相機(jī)與錄音,去河邊找鬼湾趾。 笑死芭商,一個(gè)胖子當(dāng)著我的面吹牛派草,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铛楣,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼近迁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蛉艾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤衷敌,失蹤者是張志新(化名)和其女友劉穎勿侯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缴罗,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡助琐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了面氓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兵钮。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舌界,靈堂內(nèi)的尸體忽然破棺而出掘譬,到底是詐尸還是另有隱情,我是刑警寧澤呻拌,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布葱轩,位于F島的核電站,受9級(jí)特大地震影響藐握,放射性物質(zhì)發(fā)生泄漏靴拱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一猾普、第九天 我趴在偏房一處隱蔽的房頂上張望袜炕。 院中可真熱鬧,春花似錦初家、人聲如沸偎窘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽评架。三九已至,卻和暖如春炕泳,著一層夾襖步出監(jiān)牢的瞬間纵诞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工培遵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浙芙,地道東北人登刺。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗡呼,于是被迫代替她去往敵國(guó)和親纸俭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容