需求
- 额度 15000或自定义
- 实现购物商城,买东西加入 购物车,调用信用卡接口结账
- 可以提现,手续费5%
- 支持多账户登录
- 支持账户间转账
- 记录每月日常消费流水
- 提供还款接口
- ATM记录操作日志
- 提供管理接口,包括添加账户、用户额度,冻结账户等。。。
- 用户认证用装饰器
需求分析
- 额度,初始化为15000,可以写入一个文件里balance.txt
- 购物车应用,可以参考购物车作业,整个购物车可以放到一个函数里,需要调用信用卡接口,就需要调用信用卡模块了,购物车脚本可以和信用卡的放在一起
- 提现,余额扣除提现金额*(1 + 0.05) 扣除金额不得大于余额的一半,提现完了之后扣除余额
- 多账户登陆,用户名密码写入一个文件里,参考登陆接口作业
- 账户之间转账,用户名对应的余额 - 转账金额,转账账户名对应的余额 + 转账金额
- 记录流水,还需要写一个流水文件,记录消费商品,金额,前面还需要加时间
- 还款接口,可以理解为向余额添加
- ATM操作记录
- 参考购物车作业里的
manage.py
- 装饰器,我理解应该是不同的操作,给需要密码验证的,加上输入密码验证模块,就像真正的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()
结构:
我们先来确定程序的结构
-atm
--\bin
---atm.py
---shopping.py
---manager.py
--\core
---各类程序模块
--\logs
---atm.log
---cust.log
其中bin目录为执行入口目录,atm.py
是ATM仿真程序的启动入口,shopping.py
是购物车程序的启动入口,manager.py
是管理账户程序的启动入口
core目录下主要放置各类程序模块
logs目录下主要放置操作流水记录日志,atm.log是ATM操作记录,cust.log是信用卡消费记录
setting目录下主要放置配置文件
流程图
我们先来确定atm的流程图
然后是购物车的流程图
最后是manager的流程图
实现
用户数据存放
考虑之前用字典存放用户账户名和密码,这次多了一个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
登陆接口
参考之前的作业,登录接口的主逻辑我们这样写:
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
的读取列表,登录接口里对用户输入的用户名的判断,是否在列表里。
信用卡
登录接口完成之后,我们再来一一实现信用卡功能的各个模块。
我把信用卡功能分为消费(即支付),查余额,查账单,转账,提现,还款等功能块。我们一个个来实现。
还记得我们的账户余额是写在用户信息的文件里,作为二级字典的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
是提取出来的字典。
一些基本动作
我们在写程序时,常常会遇到一些动作是频繁做的,比如扣除余额(消费,提现,转账都会用到),添加余额(还款,收到转账),还有判断余额是否充足,是否满足动作(消费,提现)所需的金额。这些可以复用的代码,我们就把它做成函数,需要时调用好了。
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'
余额的删减都需要对整个字典进行修改(这样返回数据时,接受数据的模块处理更方便,直接把data写入文件),判断余额是否满足动作所需金额bill的函数,我们返回是'success'和'failure',这样调用函数的模块更容易判断是否满足,直接根据收到的字符来判断。
日志记录
我们要有日志记录功能,记录我们每一次的消费,要有消费时间,消费项目,金额,消费记录这个动作做成模块,其他模块可以复用:
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目录下的,同时还要根据用户不同创建不同的日志信息,这样方便区分。
我们用user_dir代表logs下的用户文件夹,当不存在时,创建文件夹
cust_log代表用户文件夹下的cust.log文件,具体的信息盛放在里面。
接受的形参分别代表用户名,商品名(购物车列表),金额
调用time模块,用time.strftime()
方法取到年月日小时分秒级别的时间,用制表符写入文件
同理,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()
接受的形参分别为用户名,动作,金额。
支付模块
我们写一个支付函数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')
以上几个函数基本实现了一个信用卡的基本功能
完整的代码
#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')
单独测试每个模块也是没问题的。这样 我们就可以继续写下去了。
购物车程序
这里可以参考之前的作业,再加上一个调用信用卡模块
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")
我们先进入while循环,打印商品列表,让用户输入选择,加入购物车列表,q是退出,pay是支付,当金额是0时不需要调用信用卡模块。
支付大于0时调用信用卡模块,进入支付接口,从支付接口那里收到'success'或者'failure'的判断,做成相应动作。
然后是管理模块
也是参考之前的作业,调用现成的函数,就完成了
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目录下实现启动接口
购物车接口
这边只是需要调用购物车模块,只是需要注意现在购物车程序跟核心模块不在一个目录里,注意调用模块时的路径
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目录放进系统变量,调用下面的模块文件
管理程序
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目录放进系统变量里。
atm启动接口
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')
主要是打印可操作项,对输入做判断,调用响应的模块,也是需要注意模块调用时的添加系统变量。
用户认证用装饰器
装饰器的样式这样:
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()
函数就可以去掉装饰器了。
坑:
- 所有用的文件都需要写成变量形式啊,因为启动入口目录下面没有啊,而且不能写死,必须用
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。