程序框图 (消费模块暂未写入)

bin:程序执行


  1. import os
  2. import sys
  3. base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  4. print(base_dir)
  5. sys.path.append(base_dir)
  6.  
  7. from core import main
  8.  
  9. if __name__ == '__main__': #当作为脚本直接运行的时候,此时__name__等于__main__,当作为模块导入的时候,__name__为文件名但不带.py,故不运行if后语句。
  10. main.run()

atm.py

config:配置文件


  1. import os
  2. import sys
  3. import logging
  4. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  5.  
  6. DATABASE = {
  7. 'engine': 'file_storage', #support mysql,postgresql in the future
  8. 'name':'accounts',
  9. 'path': "%s/db" % BASE_DIR
  10. }
  11.  
  12. LOG_LEVEL = logging.INFO
  13. LOG_TYPES = {
  14. 'transaction': 'transactions.log',
  15. 'access': 'access.log',
  16. '':'11111.log'
  17. }
  18.  
  19. TRANSACTION_TYPE = {
  20. 'repay':{'action':'plus', 'interest':0},
  21. 'withdraw':{'action':'minus', 'interest':0.05},
  22. 'transfer':{'action':'minus', 'interest':0.05},
  23. 'consume':{'action':'minus', 'interest':0},
  24. }

settings

core:程序主要代码


  1. import json
  2. import time
  3. from core import db_handler
  4. from conf import settings
  5.  
  6. def load_current_balance(account_id):
  7. '''
  8. return account balance and other basic info
  9. :param account_id:
  10. :return:
  11. '''
  12. db_path = db_handler.db_handler(settings.DATABASE)
  13. account_file = "%s/%s.json" %(db_path,account_id)
  14. with open(account_file) as f:
  15. acc_data = json.load(f)
  16. return acc_data
  17. def dump_account(account_data):
  18. '''
  19. after updated transaction or account data , dump it back to file db
  20. :param account_data:
  21. :return:
  22. '''
  23. db_path = db_handler.db_handler(settings.DATABASE)
  24. account_file = "%s/%s.json" %(db_path,account_data['id'])
  25. with open(account_file, 'w') as f:
  26. acc_data = json.dump(account_data,f)
  27.  
  28. return True

accounts

  1. import os
  2. from core import db_handler
  3. from conf import settings
  4. from core import logger
  5. import json
  6. import time
  7.  
  8. def acc_auth(account,password):
  9. '''
  10. account auth func
  11. :param account: credit account number
  12. :param password: credit card password
  13. :return: if passed the authentication , retun the account object, otherwise ,return None
  14. '''
  15. db_path = db_handler.db_handler(settings.DATABASE)
  16. account_file = "%s/%s.json" %(db_path,account)
  17. print(account_file) #base_dir + accounts + account.json
  18. if os.path.isfile(account_file): #判断文件名是否存在,存在执行下面语句
  19. with open(account_file,'r') as f:
  20. account_data = json.load(f)
  21. if account_data['password'] == password:
  22. exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))
  23. if time.time() >exp_time_stamp:
  24. print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account)
  25. else: #passed the authentication
  26. return account_data
  27. else:
  28. print("\033[31;1mAccount ID or password is incorrect!\033[0m")
  29. else:
  30. print("\033[31;1mAccount [%s] does not exist!\033[0m" % account)
  31.  
  32. def acc_login(user_data,log_obj):
  33. '''
  34. account login func
  35. :user_data: user info data , only saves in memory
  36. :return:
  37. '''
  38. retry_count = 0
  39. while user_data['is_authenticated'] is not True and retry_count < 3 :
  40. account = input("\033[32;1maccount:\033[0m").strip()
  41. password = input("\033[32;1mpassword:\033[0m").strip()
  42. auth = acc_auth(account, password)
  43. if auth: #not None means passed the authentication
  44. user_data['is_authenticated'] = True
  45. user_data['account_id'] = account
  46. #print("welcome")
  47. return auth
  48. retry_count +=1
  49. else:
  50. log_obj.error("account [%s] too many login attempts" % account)
  51. exit()

登陆认证

  1. def file_db_handle(conn_params):
  2. '''
  3. parse the db file path
  4. :param conn_params: the db connection params set in settings
  5. :return:
  6. '''
  7. print('file db:',conn_params)
  8. db_path ='%s/%s' %(conn_params['path'],conn_params['name'])
  9. return db_path
  10.  
  11. def mysql_db_handle(conn_parms):
  12. pass
  13. def db_handler(conn_parms):
  14. '''
  15. connect to db
  16. :param conn_parms: the db connection params set in settings
  17. :return:a
  18. '''
  19.  
  20. if conn_parms['engine'] == 'file_storage':
  21. return file_db_handle(conn_parms)
  22.  
  23. if conn_parms['engine'] == 'mysql':
  24. return mysql_db_handle(conn_parms)

数据存储路径

  1. import logging
  2. from conf import settings
  3.  
  4. def logger(log_type):
  5.  
  6. #create logger
  7. logger = logging.getLogger(log_type)
  8. logger.setLevel(settings.LOG_LEVEL)
  9.  
  10. # create console handler and set level to debug
  11. ch = logging.StreamHandler()
  12. ch.setLevel(settings.LOG_LEVEL)
  13.  
  14. # create file handler and set level to warning
  15. log_file = "%s/log/%s" %(settings.BASE_DIR, settings.LOG_TYPES[log_type])
  16. fh = logging.FileHandler(log_file)
  17. fh.setLevel(settings.LOG_LEVEL)
  18. # create formatter
  19. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  20.  
  21. # add formatter to ch and fh
  22. ch.setFormatter(formatter)
  23. fh.setFormatter(formatter)
  24.  
  25. # add ch and fh to logger
  26. logger.addHandler(ch)
  27. logger.addHandler(fh)
  28.  
  29. return logger

日志

  1. from core import auth
  2. from core import accounts
  3. from core import logger
  4. from core import accounts
  5. from core import transaction
  6. import time
  7.  
  8. #transaction logger
  9. trans_logger = logger.logger('transaction')
  10. #access logger
  11. access_logger = logger.logger('access')
  12.  
  13. #temp account data ,only saves the data in memory
  14. user_data = {
  15. 'account_id':None,
  16. 'is_authenticated':False,
  17. 'account_data':None
  18.  
  19. }
  20.  
  21. def account_info(acc_data):
  22. print(user_data)
  23. def repay(acc_data):
  24. '''
  25. print current balance and let user repay the bill
  26. :return:
  27. '''
  28. account_data = accounts.load_current_balance(acc_data['account_id']) #获取用户id,就是要用实时的最新数据,为了安全
  29. #for k,v in account_data.items():
  30. # print(k,v )
  31. current_balance= ''' --------- BALANCE INFO --------
  32. Credit : %s
  33. Balance: %s''' %(account_data['credit'],account_data['balance'])
  34. print(current_balance)
  35. back_flag = False
  36. while not back_flag:
  37. repay_amount = input("\033[33;1mInput repay amount:\033[0m").strip()
  38. if len(repay_amount) >0 and repay_amount.isdigit():
  39. #print('ddd 00')
  40. new_balance = transaction.make_transaction(trans_logger,account_data,'repay', repay_amount)
  41. if new_balance:
  42. print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
  43.  
  44. else:
  45. print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % repay_amount)
  46.  
  47. if repay_amount == 'b':
  48. back_flag = True
  49. def withdraw(acc_data):
  50. '''
  51. print current balance and let user do the withdraw action
  52. :param acc_data:
  53. :return:
  54. '''
  55. account_data = accounts.load_current_balance(acc_data['account_id'])
  56. current_balance= ''' --------- BALANCE INFO --------
  57. Credit : %s
  58. Balance: %s''' %(account_data['credit'],account_data['balance'])
  59. print(current_balance)
  60. back_flag = False
  61. while not back_flag:
  62. withdraw_amount = input("\033[33;1mInput withdraw amount:\033[0m").strip()
  63. if len(withdraw_amount) >0 and withdraw_amount.isdigit():
  64. new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount) # new_balance就是 函数返回值 acount_data
  65. if new_balance:
  66. print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
  67.  
  68. else:
  69. print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % withdraw_amount)
  70.  
  71. if withdraw_amount == 'b':
  72. back_flag = True
  73.  
  74. def transfer(acc_data):
  75. pass
  76. def pay_check(acc_data):
  77. pass
  78. def logout(acc_data):
  79. pass
  80. def interactive(acc_data):
  81. '''
  82. interact with user
  83. :return:
  84. '''
  85. menu = u'''
  86. ------- Oldboy Bank ---------
  87. \033[32;1m1. 账户信息
  88. 2. 还款(功能已实现)
  89. 3. 取款(功能已实现)
  90. 4. 转账
  91. 5. 账单
  92. 6. 退出
  93. \033[0m'''
  94. menu_dic = {
  95. '': account_info,
  96. '': repay,
  97. '': withdraw,
  98. '': transfer,
  99. '': pay_check,
  100. '': logout,
  101. }
  102. exit_flag = False
  103. while not exit_flag:
  104. print(menu)
  105. user_option = input(">>:").strip()
  106. if user_option in menu_dic:
  107. menu_dic[user_option](acc_data) #比如选择了2 ,则运行 repay(acc_data),调用repay函数
  108.  
  109. else:
  110. print("\033[31;1mOption does not exist!\033[0m")
  111. def run():
  112. '''
  113. this function will be called right a way when the program started, here handles the user interaction stuff
  114. :return:
  115. '''
  116. acc_data = auth.acc_login(user_data,access_logger) #userdata作为条件,access_logger作为日志信息传入
  117. if user_data['is_authenticated']:
  118. user_data['account_data'] = acc_data #acc_data 即是用户信息 1234.json
  119. interactive(user_data) #交互

主程序

  1. from conf import settings
  2. from core import accounts
  3. from core import logger
  4. #transaction logger
  5.  
  6. def make_transaction(log_obj,account_data,tran_type,amount,**others):
  7. '''
  8. deal all the user transactions
  9. :param account_data: user account data
  10. :param tran_type: transaction type
  11. :param amount: transaction amount
  12. :param others: mainly for logging usage
  13. :return:
  14. '''
  15. amount = float(amount)
  16. if tran_type in settings.TRANSACTION_TYPE:
  17.  
  18. interest = amount * settings.TRANSACTION_TYPE[tran_type]['interest']
  19. old_balance = account_data['balance']
  20. if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':
  21. new_balance = old_balance + amount + interest
  22. elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':
  23. new_balance = old_balance - amount - interest
  24. #check credit
  25. if new_balance <0:
  26. print('''\033[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is
  27. [%s]''' %(account_data['credit'],(amount + interest), old_balance ))
  28. return
  29. account_data['balance'] = new_balance
  30. accounts.dump_account(account_data) #save the new balance back to file
  31. log_obj.info("account:%s action:%s amount:%s interest:%s" %
  32. (account_data['id'], tran_type, amount,interest) )
  33. return account_data
  34. else:
  35. print("\033[31;1mTransaction type [%s] is not exist!\033[0m" % tran_type)

交易种类

db:用户信息存储


  1. {"id": "gkx", "password": "", "credit": 15000, "balance": 15000, "enroll_date": "2016-01-02", "expire_date": "2021-01-01", "pay_day": 22, "status": 0}

python项目练习的更多相关文章

  1. 给缺少Python项目实战经验的人

    我们在学习过程中最容易犯的一个错误就是:看的多动手的少,特别是对于一些项目的开发学习就更少了! 没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用 ...

  2. 正确地组织python项目的结构

    统一的项目结构 写了不少python项目后, 越来越认识到python项目结构重要性. 不管项目是否要开源, 是否要提交pypi, 项目结构的一致性带来的好处还有很多: 多人合作开发大家都有个基本的g ...

  3. eclipse中建python项目并运行

    1. Help → Install New Software 2.Enter http://pydev.org/updates 3.点击Click "Next" and " ...

  4. 使用 tox flake8 pytest 规范 python 项目

    使用 tox flake8 pytest 规范 python 项目 python 中有些很好的工作来规范整个项目的开发,而其中使用较多的就是使用 tox . flake8 . pytest . tox ...

  5. 2013流行Python项目汇总

    2013流行Python项目汇总 转自:http://www.kankanews.com/ICkengine/archives/102963.shtml Python作为程序员的宠儿,越来越得到人们的 ...

  6. python项目

    python实战项目: http://www.the5fire.com/category/python实战/ python基础教程中的十个项目: python项目练习一:即时标记 python项目练习 ...

  7. Eclipse开发Python项目

    最近倒腾python自带的开发工具idle,用的很不习惯,还是用Eclipse编写python项目方便(自动补齐,智能报错,调试方便),下面就说说怎么用Eclipse编写python代码吧~ 1.安装 ...

  8. 以正确的方式开源 Python 项目

    以正确的方式开源 Python 项目 大多数Python开发者至少都写过一个像工具.脚本.库或框架等对其他人也有用的工具.我写这篇文章的目的是让现有Python代码的开源过程尽可能清 晰和无痛.我不是 ...

  9. 流行的Python项目汇总

    年有哪些流行的Python项目呢?下面,我们一起来看下. 一.测试和调试 python_koans :Python Koans 算 “Ruby Koans” 的一部分,作为交互式教程,可以学习 TDD ...

  10. 创建成功的Python项目

    创建成功的Python项目 前端开发工具技巧介绍—Sublime篇 SEO在网页制作中的应用 观察者模式 使用D3制作图表 英文原文:Create successful Python projects ...

随机推荐

  1. 动物管理员--zooKeeper-01

    ZooKeeper集群角色介绍: 最典型集群模式:Master/Slave 模式(主备模式).在这种模式中,通常 Master 服务器作为主服务器提供写服务,其他的 Slave 服务器从服务器通过异步 ...

  2. 关于lazyload的实现原理

    核心原理是: 1 设置一个定时器,计算每张图片是否会随着滚动条的滚动,而出现在视口(也就是浏览器中的 展现网站的空白部分 )中: 2 为<img>标签设置一个暂存图片URL的自定义属性(例 ...

  3. winfrom进程、线程、用户控件

    一.进程 一个进程就是一个程序,利用进程可以在一个程序中打开另一个程序. 1.开启某个进程Process.Start("文件缩写名"); 注意:Process要解析命名空间. 2. ...

  4. Java 五大原则

    1.单一职责 不论是在设计类,接口还是方法,单一职责都会处处体现,单一职责的定义:我们把职责定义为系统变化的原因.所有在定义类,接口,方法的时候.定义完以后再去想一想是不能多于一个的动机去改变这个类, ...

  5. 微信公众号开发流程,jssdk的使用以及签名算法的实现

    一 开发流程 1 基本配置-登录自己的公众号 A:新型微信认证,认证过的企业号才可以进行自定义菜单中的连接跳转: B:开发基本配置里面进行开发者iD查询,密码查询和重置和ip白名单配置: C:公众号设 ...

  6. nginx与PHP配置

    一.安装依赖包 yum -y install  libxml2  libxml2-devel  openssl  openssl-devel  curl  curl-devel libjpeg  li ...

  7. LeetCode #002# Add Two Numbers(js描述)

    索引 思路1:基本加法规则 思路2:移花接木法... 问题描述:https://leetcode.com/problems/add-two-numbers/ 思路1:基本加法规则 根据小学学的基本加法 ...

  8. 基本数据类型大总结(int,str,list,dict,tuple)

    python基本数据类型 int==>整数,主要用来进行数学运算 str==>字符串,可以保存单一数值 bool==>判断真假,true,false list==>存储大量数据 ...

  9. Ansible 的安装

    On Fedora: $ sudo dnf install ansible On RHEL and CentOS: $ sudo yum install ansible On Ubuntu: $ su ...

  10. HTML基础(2)——边框

    边框:(尺寸 样式 颜色) div{border:1px solid red;} 样式可能的值: dotted(点状边框,在大多数浏览器里呈现实线) dashed(虚线.在大多数浏览器中呈现为实线) ...