计算机教程

当前位置:3522.com > 计算机教程 > 学习python之路--Day4:ATM程序

学习python之路--Day4:ATM程序

来源:http://www.4sports-uk.com 作者:3522.com 时间:2019-05-10 16:45

二.程序流程图

完整的代码

#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')

单独测试每个模块也是没问题的。这样 我们就可以继续写下去了。

  1. 拥有用户接口和商家接口
  2. 用户能够进行消费记录查询,充值,购物等功能,消费记录存储于数据库
  3. 商家可以进行商品的增删改等操作

需求分析

  1. 额度,初始化为15000,可以写入一个文件里balance.txt
  2. 购物车应用,可以参考购物车作业,整个购物车可以放到一个函数里,需要调用信用卡接口,就需要调用信用卡模块了,购物车脚本可以和信用卡的放在一起
  3. 提现,余额扣除提现金额*(1 0.05) 扣除金额不得大于余额的一半,提现完了之后扣除余额
  4. 多账户登陆,用户名密码写入一个文件里,参考登陆接口作业
  5. 账户之间转账,用户名对应的余额 - 转账金额,转账账户名对应的余额 转账金额
  6. 记录流水,还需要写一个流水文件,记录消费商品,金额,前面还需要加时间
  7. 还款接口,可以理解为向余额添加
  8. ATM操作记录
  9. 参考购物车作业里的manage.py
  10. 装饰器,我理解应该是不同的操作,给需要密码验证的,加上输入密码验证模块,就像真正的ATM那样,非重要的操作可以不需要密码

进一步思考:
balance和用户密码可以写成字典形式,用pickle导入到文件,到时候在load出来,方便处理,按用户名,密码,余额的形式对应起来,写在一个文件里。

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()

购物车程序写在shopplist.py里,功能有选择商品,加入购物车,确认付款,到支付接口,完成后返回信息。
支付接口写在credit.py ,支付函数payment(),支付需要调用修改余额函数write_balance() 记录账单记录函数consumer_logger()
提现接口也可以写在credit.py里,提现函数withdraw(),提现需要调用修改余额函数write_balance(),记录操作记录atm_logger()

账户间转账写在credit.py里,转账函数transfer(),转账需要提供转账账户名,转账金额,需要调用修改余额函数write_balance(),记录操作记录atm_logger()
还款接口也可以写在credit.py里,还款函数repay(),需要调用修改余额函数write_balance(),记录操作记录atm_logger()

3522.com 1

用户数据存放

考虑之前用字典存放用户账户名和密码,这次多了一个balance,那就字典里增加一个key叫'balance',字典形式这样的:
{'test': {'balance': 11000.0, 'passwd': 'test'}, 'root': {'balance': 9000.0, 'passwd': 'python'}}

用户名对应一个字典,内字典key是passwd和balance,对应用户的密码和余额,在实现程序之前,先创建这个user.info文件
我用pickle.dump方法把测试用户写入文件:

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的方法,写一个product.txt的文件,用来存放商品信息,商品有名称和价格,参考之前的购物车项目,我们做成列表类型。
product.txt的脚本可以跟之前写user.info文件的脚本合并,做成一个初始化脚本:

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()

初始化数据好了之后,已经拥有了一些测试账号和商品,开始做我们的登陆接口login

  程序大致流程图如下:

用户认证用装饰器

装饰器的样式这样:

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

        func(*args,**kwargs)

    return decorator

@login
def func():
    pass

func()

我们对login()函数进行改造

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()

这样测试,可以正常实现功能,现在要融入其他模块中。
在同级目录下写一个测试文件

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

测试,可以实现,于是移植到其他模块里。

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')

测试可以实现功能

注意不止credit.py需要用到认证,其他文件可能也需要,像是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()函数就可以去掉装饰器了。

  DataAccess_txt.py程序代码如下:

登陆接口

参考之前的作业,登录接口的主逻辑我们这样写:

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

输入帐号密码,判断是否存在用户,之后判断密码是否是字典里用户名对应的二级字典'passwd'对应的value,稍后这个需要做成装饰器,我们先做成一个可调用的函数形式:

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

函数返回的值我们暂时定为输入的用户名。

还有一个冻结账户的需求,这里还需要有个blacklist.txt用来存放被冻结的账户,参考之前的作业,黑名单做成列表,存放用户名,pickle序列化到文件里。
在初始化脚本里加上创建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()

创建好之后,完善登录接口的逻辑,我们把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

新增逻辑对blacklist.txt的读取列表,登录接口里对用户输入的用户名的判断,是否在列表里。

  ShoopingCar.py程序代码如下:

实现


3522.com 2

坑:

  • 所有用的文件都需要写成变量形式啊,因为启动入口目录下面没有啊,而且不能写死,必须用os.path.dirname方式加os.sep加文件名拼贴才行啊!!
  • credit里的consumer_logger()函数需要按不同账户创建不同的log啊啊啊!
  • 自己写的模块A import了另一个自己写的模块B,启动程序那里还需要加上模块B所在路径的系统搜索路径啊~不然from package import 模块A的时候,模块A再import 模块B,这个时候不知道从哪里找模块B,因为启动程序的系统路径里找不到模块B;如果是import package,运行__init__.py的时候,from . import 模块B,这个时候启动程序的系统搜索路径里也找不到B。
import DataAccess_txt#要导入DataAccess_txt.py这个模块


while True:
    Num=input("1.用户界面,2.商家界面,输入q退出 :")
    if Num.isdigit():
        Num = int(Num)
        if Num == 1:
            username = input("Please Input The Username :")
            DataAccess_txt.user_printAccountBalance(username)
            while True:
                UserChoose = input("1.查询购物记录,2.购物,3.充值,输入q返回上级目录 :")
                if UserChoose.isdigit():
                    UserChoose = int(UserChoose)
                    if UserChoose == 1:
                        DataAccess_txt.user_RecordsConsumption(username)#查询购物记录
                    elif UserChoose == 2:
                        DataAccess_txt.user_ShoopCar(username)#购物车
                    elif UserChoose == 3:
                        value = int(input("请输入充值金额 :"))
                        DataAccess_txt.user_TopUp(username,value)#充值
                elif UserChoose=='q':
                    break
                else:
                    pass

        elif Num == 2:#商家界面
            DataAccess_txt.search_data_access()#打印商品信息和库存
            while True:
                UserChoose = input("1.添加商品,2.修改商品信息,3.删除商品,输入q返回上级目录 :")
                if UserChoose.isdigit():
                    UserChoose = int(UserChoose)
                    if UserChoose==1:
                        goodsname=input("请输入商品名 :")
                        goodsvalue=int(input("请输入商品价格 :"))
                        goodnum = int(input("请输入商品数量 :"))
                        DataAccess_txt.add_goods_opt(goodsname,goodsvalue,goodnum)#商品添加操作
                    elif UserChoose==2:
                        goodsname = input("请输入要修改的商品名 :")
                        goodsvalue = int(input("请输入商品价格 :"))
                        goodnum = int(input("请输入商品数量 :"))
                        DataAccess_txt.Change_goods_info(goodsname, goodsvalue,goodnum)
                    elif UserChoose==3:
                        goodsname = input("请输入要删除的商品名 :")
                        DataAccess_txt.delet_goods_opt(goodsname)
                elif UserChoose=='q':
                    break
                else:
                    pass
        else:
            pass
    elif Num == 'q':
        break
    else:
        pass

信用卡

登录接口完成之后,我们再来一一实现信用卡功能的各个模块。

我把信用卡功能分为消费(即支付),查余额,查账单,转账,提现,还款等功能块。我们一个个来实现。

还记得我们的账户余额是写在用户信息的文件里,作为二级字典的value存在的吗?消费,转账,提现,还款都要对余额有个修改操作,我们可以统一做成一个写入余额的功能模块。
实现写入文件的模块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()

上面的代码,我是打开相对路径下的user.info文件,其实是跟balance_module是属于同一目录的,写成info_path可以方便日后迁移user.info路径。
函数write_balance接受的是一个字典,模块会把这个字典写入文件,覆盖之前的内容,这就要求我们传入的字典是带有所有用户信息的,一个已经调整好的字典,不会再有变动了。
这样写的好处是,所有信息修改完成之后,才会写入文件,这样下次读取的文件内容就是最新的了。这个道理我们在上一篇中已经探讨过。

读取user.info文件的函数
info_path的路径即为user.info的相对于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是提取出来的字典。

  3522.com 3

支付模块

我们写一个支付函数payment来实现逻辑:

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

可以看到我们需要调用用户认证接口,因为到付款界面了,必须知道银行账户。
调用了读取用户信息字典的read_info()函数,将字典提取出来
调用了judgment()来判断用户对应的余额是否满足
如果收到的是'success',调用扣除余额的函数,将字典写入文件的函数,消费日志记录函数

以上函数我们都已经写出来了。
然后函数返回的结果是成功或者失败。很容易理解对吧。

转账模块就是一个用户余额减少,另一个用户余额增加,可以这么写(为了直观,我没有把add() subtract() judgment() atm_logger()这些调用的函数写出来,下面几个也是如此):

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')

提现模块也很好写,用户余额减少,同时判断余额一半是否大于提现的金额:

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')

也是调用了一堆现成的函数,把它们拼贴起来。

还款,就是新增余额:

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')

以上几个函数基本实现了一个信用卡的基本功能

  要注意的是必须要记得导入模块,不然没有办法使用自己编写的数据操作接口,ShoopingCar.py的第一行代码就是模块的导入,调用DataAccess_txt.py的数据操作接口时,以delet_goods_opt()删除商品信息接口为例,调用方法是DataAccess_txt.delet_3522.com,goods_opt()。

流程图

我们先来确定atm的流程图

3522.com 4

atm

然后是购物车的流程图

3522.com 5

shopping

最后是manager的流程图

3522.com 6

manager

本文由3522.com发布于计算机教程,转载请注明出处:学习python之路--Day4:ATM程序

关键词: 3522.com

上一篇:3522.com:WEB前端规范命名

下一篇:没有了