软件开发的目录规范

建立文件夹

为了提高程序的可读性与可维护性,我们应该为软件设计良好的目录结构,这与规范的编码风格同等重要。软件的目录规范并无硬性标准,只要清晰可读即可

以ATM购物车项目为例:

首先需要建立一个项目文件夹,例如项目名称ATM,这个ATM的大文件夹下需要有几个子文件夹:

bin文件夹:用于存放指令文件,可执行指令,例如:start.py

conf文件夹:配置性的文件,存放一些变量,运行软件时需要从中读取一些变量值,例如:settings.py

db文件夹:放数据库相关的操作代码,例如:db_handle.py

core文件夹:核心代码,例如:src.py

log文件夹:存放日志,查看软件运行时记录的一些日志数据,例如:access.log

lib文件夹:库目录,

db文件夹:存放数据

readme.md:类似于软件说明书

搭框架

在core文件夹下建立src.py文件

==============================在 ATM/core/src.py下================================
def login():
print('登录功能') # 简易的功能 def register():
print('注册功能') def transfer():
print('转账功能') function_dic = {
'1':['登录',login],
'2':['注册',register],
'3':['转账',transfer]
} def run(): # src文件只负责功能性的定义,不负责程序的运行,到时候调用放在start.py文件里面
while True:
print('0 ️ 退出')
for k in function_dic:
print('%s ️ %s' %(k,function_dic[k][0]))
choice = input('输入功能指令>>>')
if choice == '0':
break
if choice in function_dic:
function_dic[choice][1]()
else:
print('指令不存在,重新键入')

在bin文件夹下建立start.py文件

==============================在 ATM/bin/start.py下================================
# 为了软件便于管理维护我们将软件进行拆分
# 让 start.py 能够跨文件调的到 src.py 里面的函数 run,那我们就需要将src文件的文件夹路径加入环境变量
import sys sys.path.append(r'/Users/jessewu/PycharmProjects/pythonProject/test01/study miscellaneous/规范目录/ATM/core') # 将src文件的文件夹路径加入环境变量 import src # 这样就能正常跨文件调用src的功能了 if __name__ == '__main__': # 当这个文件作为主文件运行时就执行里面的子代码 在执行文件里面加上这个更规范一点
src.run()

但是上述代码仍是有问题的因为我们可能会导入到的文件很多,那我们每次导入都需要添加到环境变量,这样就比较麻烦,我们改进一下:

==============================在 ATM/bin/start.py下================================
import sys sys.path.append(r'/Users/jessewu/PycharmProjects/pythonProject/test01/study miscellaneous/规范目录/ATM') # 将文件的软件根目录直接加入环境变量 这样就能用到哪个直接导入 from core import src
if __name__ == '__main__':
src.run()

这样我们又碰到另一个问题,我们写的是一个软件,当用户将这个软件安装到其它电脑的时候,文件路径和我们写的时候不一样,那这样软件就无法运行。我们需要再改动一下,将文件路径写活了,让它在别的电脑也能运行:

==============================在 ATM/bin/start.py下================================
import sys import os # 导入os模块 调用__file__功能,它能够直接动态获取到当前文件的绝对路径 BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # 获取但前文件文件夹的文件夹,也就是副副文件夹, sys.path.append(BASE_DIR) # 这样就能够动态获取 from core import src
if __name__ == '__main__':
src.run()

但还有更省事的办法:

==============================在 ATM/start.py下================================
# 直接将start.py文件移动到项目的根目录下面,因为当前执行文件的文件夹会自动添加到环境变量中,这样我们就不用手动添加路径了
from core import src # 直接就能导入
if __name__ == '__main__':
src.run()

接下来我们有一个需求,日志需求,我们需要记录日志,日志功能不是用户需要用到的,他是一个其他功能都可能需要调用到的功能,我们将它放在lib文件夹下,创建文件common.py:

==============================在 ATM/lib/common.py下================================
import time
def logger(msg):
with open(r'/Users/jessewu/PycharmProjects/pythonProject/test01/study miscellaneous/规范目录/ATM/log/access.log',\
mode='at',encoding='utf8')as f:
f.write('%s %s\n' %(time.strftime('%Y-%m-%d %H:%M:%s'),msg))
# 简易的日志功能
==============================在 ATM/core/src.py下================================
from lib.common import logger # 需要调用到lib下common里面的logger功能,需要导入一下,需要注意的是这里的.是路径分隔符的意思 def login():
print('登录功能')
logger('登陆了') def register():
print('注册功能')
logger('有人注册了') def transfer():
print('转账功能')
logger('转出了一笔钱') function_dic = {
'1': ['登录', login],
'2': ['注册', register],
'3': ['转账', transfer]
}
def run():
while True:
print('0 ️ 退出')
for k in function_dic:
print('%s ️ %s' % (k, function_dic[k][0]))
choice = input('输入功能指令>>>')
if choice == '0':
logger('下线了')
break
elif choice in function_dic:
function_dic[choice][1]()
else:
print('指令不存在,重新键入')

虽然日志功能能正常记录了,但是还是老问题,记录日志的文件路径被我们写死了,需要将路径写活,且这个路径能够让用户能够配置的,在conf文件夹下创建文件setting.py:

==============================在 ATM/conf/settings.py下================================
# 需要定义一个路径变量,让它在common模块里面能够被调用到
import os BASE_DIR = os.path.dirname(os.path.dirname(__file__))
LOG_PATH = '%s/log/access.log' % BASE_DIR # 保证用户即自己能改,也可以不改就能用
==============================在 ATM/lib/common.py下================================import timefrom conf import settings  # 调用settings里面的logger功能def logger(msg):    with open('%s' %ssettings.LOG_PATH,mode='at',encoding='utf8')as f:        f.write('%s  %s\n' %(time.strftime('%Y-%m-%d %H:%M:%s'),msg))

升级需求,将写好的logger替换成系统里的logging模块,首先我们在settings.py里面定义好LOGGING_DIC,规定好日志的格式和打印形式,过滤级别,logger表示级别为每条日志打上标签,filters表示过滤,handlers表示将日志如何处理,是打印还是输出到终端:

==============================在 ATM/conf/settings.py下================================# 1、定义三种日志输出格式,日志中可能用到的格式化串如下# %(name)s Logger的名字# %(levelno)s 数字形式的日志级别# %(levelname)s 文本形式的日志级别# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有# %(filename)s 调用日志输出函数的模块的文件名# %(module)s 调用日志输出函数的模块名# %(funcName)s 调用日志输出函数的函数名# %(lineno)d 调用日志输出函数的语句所在的代码行# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒# %(thread)d 线程ID。可能没有# %(threadName)s 线程名。可能没有# %(process)d 进程ID。可能没有# %(message)s用户输出的消息# 2、强调:其中的%(name)s为getlogger时指定的名字standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \                  '[%(levelname)s][%(message)s]'simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'test_format = '%(asctime)s] %(message)s'LOGGING_DIC = {    'version': 1,    'disable_existing_loggers': False,    'formatters': {        'standard': {            'format': standard_format        },        'simple': {            'format': simple_format        },        'test': {            'format': test_format        },    },    'filters': {},    'handlers': {        #打印到终端的日志        'console': {            'level': 'DEBUG',            'class': 'logging.StreamHandler',  # 打印到屏幕            'formatter': 'simple'        },        #打印到文件的日志,收集info及以上的日志        'default': {            'level': 'DEBUG',            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转            'formatter': 'standard',            # 可以定制日志文件路径            # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录            # LOG_PATH = os.path.join(BASE_DIR,'a1.log')            'filename': LOG_PATH,  # 日志文件            'maxBytes': 1024*1024*5,  # 日志大小 5M            'backupCount': 5,            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了        },        'other': {            'level': 'DEBUG',            'class': 'logging.FileHandler',  # 保存到文件            'formatter': 'test',            'filename': 'a2.log',            'encoding': 'utf-8',        },    },    'loggers': {        #logging.getLogger(__name__)拿到的logger配置        '用户相关日志': {            'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕            'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递        },    },}

定义好之后,我们到原本的logger功能模块common.py下面将之前的蹩脚功能注释掉,重新写,定义logger函数:

==============================在 ATM/lib/common.py下================================
from conf import settings
import logging.configlogging.config.dictConfig(settings.LOGGING_DIC) # 固定用法def logger(log_name): logger1 = logging.getLogger(log_name) # log_name 使用者需要自己传日志类型名称进去 return logger1
==============================在 ATM/core/src.py下================================
import loggingfrom lib.common import loggerdef login(): print('登录功能') log = logger('用户相关日志') # 赋值给变量 log.debug('xxx登录了') # 调用级别def register(): print('注册功能') log = logger('用户相关日志') log.info('有人注册了')def transfer(): print('转账功能') log = logger('用户相关日志') log.info('转出了一笔钱')def withdraw(): print('提现功能') log = logger('用户相关日志') log.warning('提现金额过大,可能要跑')function_dic = { '1': ['登录', login], '2': ['注册', register], '3': ['转账', transfer], '4': ['提现', withdraw]}def run(): while True: print('0 ️ 退出') for k in function_dic: print('%s ️ %s' % (k, function_dic[k][0])) choice = input('输入功能指令>>>') if choice == '0': log = logger('用户相关日志') log.info('下线了') break elif choice in function_dic: function_dic[choice][1]() else: print('指令不存在,重新键入')

软件开发目录规范 ATM框架构建的更多相关文章

  1. Python 浅谈编程规范和软件开发目录规范的重要性

    最近参加了一个比赛,然后看到队友编程的代码,我觉得真的是觉得注释和命名规范的重要性了,因为几乎每个字符都要咨询他,用老师的话来说,这就是命名不规范的后续反应.所以此时的我意识到写一篇关于注释程序的重要 ...

  2. python 之 软件开发目录规范 、logging模块

    6.4 软件开发目录规范 软件(例如:ATM)目录应该包含: 文件名 存放 备注 bin start.py,用于起动程序   core src.py,程序核心功能代码   conf settings. ...

  3. python模块导入-软件开发目录规范-01

    模块 模块的基本概念 模块: # 一系列功能的结合体 模块的三种来源 """ 模块的三种来源 1.python解释器内置的模块(os.sys....) 2.第三方的别人写 ...

  4. python浅谈编程规范和软件开发目录规范的重要性

    前言 我们这些初学者,目前要做的就是遵守代码规范,这是最基本的,而且每个团队的规范可能还不一样,以后工作了,尽可能和团队保持一致,目前初学者就按照官方的要求即可 新人进入一个企业,不会接触到核心的架构 ...

  5. Python记录13:软件开发目录规范

    软件开发目录规范 开发一个软件,一个工程项目,一般应该具备以下的几个基本的文件夹和模块,当然,这并不是一成不变的,根据项目的不同会有一定的差异,不过作为一个入门级的新手,建议暂时按照以下的规范编写: ...

  6. Python模块:Re模块、附软件开发目录规范

    Re模块:(正则表达式) 正则表达式就是字符串的匹配规则 正则表达式在多数编程语言里都有相应的支持,Python里面对应的模块时re 常用的表达式规则:(都需要记住) “ . ”   #  默认匹配除 ...

  7. py 包和模块,软件开发目录规范

    目录 py 包和模块,软件开发目录规范 什么是包? 什么是模块? 软件开发目录规范 py 包和模块,软件开发目录规范 什么是包? 包指的是内部包__init__.py的文件夹 包的作用: 存放模块,包 ...

  8. python基础语法10 函数递归,模块,软件开发目录规范

    函数递归: 函数递归指的是重复 “直接调用或间接调用” 函数本身, 这是一种函数嵌套调用的表现形式. 直接调用: 指的是在函数内置,直接调用函数本身. 间接调用: 两个函数之间相互调用间接造成递归. ...

  9. day16(软件开发目录规范)

    模块的使用01 模块的循环导入问题 解决方案一: 把循环导入的语句放到名字定义的后面 解决方案二: 将循环导入语句放到函数内(先定义确定名称空间)02 区分python文件的两种用途 #当文件被执行时 ...

随机推荐

  1. 在Redis中设置了过期时间的Key,需要注意哪些问题?

    熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除. 在为key设置过期时间需要注意的事项 1. DEL/SET/GETSET等 ...

  2. C++ 继承及委托

    从内存角度看继承和多重继承 http://www.doc88.com/p-9075148832569.html 在C++中实现委托(Delegate) https://blog.csdn.net/jf ...

  3. Luogu P2754 星际转移问题

    Luogu P2754 星际转移问题 思路 首先,对于地球能否到达月球的问题,考虑使用并查集维护. 对于每艘飞船能够到达的站点,放进一个集合里,若两艘飞船的集合有交集,那么就合并两个集合,最后只要地球 ...

  4. [刘阳Java]_MySQL数据优化总结_查询备忘录

    数据库优化是在后端开发中必备技能,今天写一篇MySQL数据优化的总结,供大家看看 一.MySQL数据库优化分类 我们通过一个图片形式来看看数据优化一些策略问题 不难看出,优化有两条路可以选择:硬件与技 ...

  5. 【动画消消乐】HTML+CSS 自定义加载动画 062

    效果展示 Demo代码 HTML <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  6. python基础之while语句操作

    # i = 0# while (i < 9):# print("i ----> ",i)# i = i + 1# print(i,"i即将大于或者等于9,wh ...

  7. 【LeetCode】94. 二叉树的中序遍历

    94. 二叉树的中序遍历 知识点:二叉树:递归:Morris遍历 题目描述 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例 输入:root = [1,null,2,3] 输出:[1, ...

  8. Guava - Set集合

    当我们在统计一个字符串中每个单词出现的次数时,通常的做法是分割字符串,遍历字符串,然后放到一个map里面,来进行统计,Guava中提供了类似功能的集合,Multiset String strWorld ...

  9. WEB安全新玩法 [8] 阻止订单重复提交

    交易订单的重复提交虽然通常不会直接影响现金流和商品流,但依然会给网站运营方带来损害,如消耗系统资源.影响正常用户订单生成.制造恶意用户发起纠纷的机会等.倘若订单对象是虚拟商品,也有可能造成实际损失.订 ...

  10. python errno库与socket.connect_ex()方法的结合使用

    前言:一般socket链接会首选connect方法,该方法会一直尝试链接.那么今天展示下connect_ex()方法,该方法如果链接成功会返回0,失败会返回errno库中的errorcode中的key ...