python软件开发规范

软件开发规范

什么是软件开发规范?

好的设计项目目录结构,就和编码风格一样,是每个程序员都有的风格,但是在流水化标准化作业过程中,个性和风格是

不被鼓励的。如果你去维护一个非常不好读的项目,虽然实现逻辑并不复杂,但是对后续的维护者来说就是灾难。

 一个层次清晰的目录结构,可以提高程序的可维护性:

  1. 可读性高:

    后续维护人员可以一眼看懂目录结构,不必为复杂混乱的层次耗费大量精力。测试文件在哪,配置文件在哪会被放置在规范操作的地方,可以让后续人员快速的了解这个项目。

  2. 可维护性高:

    看清目录架构之后,维护者可以将后续新增的文件和代码按照规范放置在规定的地方,虽然后续代码和文件增多,但是项目目录并不会混乱,仍然能够快速组织良好

按照分级目录规范模拟博客园系统

一个py文件下的博客园系统:

import json,time,os
print('欢迎使用博客园系统')
flag = 1
msg = """1.请登录
2.请注册
3.进入文章页面
4.进入评论页面
5.进入日记页面
6.进入收藏页面
7.注销账号
8.退出整个程序
"""login_information = {"username": None, "status": False}
def login(func=False):"""登录函数:param func: 函数名默认为False:return: 无返回值"""time.sleep(0.1)user_name = input('请输入你要登录的用户名')pwd = input('请输入登录密码')landing_info = {}global login_informationwith open("userinfo.txt", "r", encoding="utf-8")as f1:for line in f1:x = line.strip()[:-2]num = int(line.strip()[-1])name = x.split(':', 1)[0]password = x.split(':', 1)[1]landing_info[name] = [password, num]if user_name in landing_info:count = landing_info[user_name][1] + 1if count == 3:print('你的账号已锁定,请联系管理员解锁')else:while count < 3:if pwd == landing_info[user_name][0]:login_information["username"] = user_namelogin_information["status"] = Trueprint("登录成功")if func:func()breakelse:print(f"你的密码输入错误,剩余次数为{3 - count},请重新键入")pwd = input('请重新输入密码:')landing_info[user_name][1] = count + 1count += 1else:print('你的账户已锁定,请联系管理员处理')with open('userinfo.txt', 'r', encoding='utf-8')as f1, open('user.txt', 'w', encoding='utf-8') as f2:f1.seek(0, 0)for i in f1:if i.strip().split(':', 1)[0] == user_name:i = i.strip()content = i[:-1] + "3"f2.write(content + '\n')else:f2.write(i)os.remove('userinfo.txt')os.rename('user.txt', 'userinfo.txt')else:print('你输入的账号不存在,请先去注册')def wrapper(f):"""操作认证:param f: 操作函数:return:"""def inner():time.sleep(1)if login_information["status"]:f()else:login(f)return innerdef registration():"""注册函数:return:"""user_info = {}num = 3while num:user_name = input('请输入要注册的用户名:')pwd = input('请输入要注册的密码:')num -= 1lst_name = list(range(65, 91)) + list(range(97, 123))for i in user_name:if (i.isdecimal()== True or ord(i) in lst_name) and 6 <= len(pwd) <= 14:passelse:print('用户名或密码无效,请重新输入')if num == 0:print('注册失败')breakelse:with open('userinfo.txt', 'r+', encoding='utf-8')as f:for i in f:i = i.strip()[:-2]k, v = i.split(':')user_info[k] = vif user_name in user_info:print('用户名已存在,请重新输入用户名')if num == 0:print('注册失败')continueelse:f.write(f"\n{user_name}:{pwd}:0")choose = input('你已经注册成功,是否重新注册(重新注册键入1)')if choose == '1':num = 3else:print('注册成功,你可以去嚯嚯了')time.sleep(1)num = 3break@wrapper
def article():"""文章页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入文章页面!")@wrapper
def comment():"""评论页面:return:"""num = 1global login_informationprint(f"欢迎{login_information['username']}进入评论页面!")with open('com','r',encoding="utf-8") as f:for i in f:s = i.strip()print(json.loads(s))num += 1choose = input("是否评论Y or N")if choose == "Y":com = input("请输入评论:")with open('com','a',encoding="utf-8") as f2:com1 = f"{num}楼 - {login_information['username']}:{com}"f2.write(json.dumps(com1,ensure_ascii=False)+"\n")@wrapper
def diary():"""日记页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入日记页面!")@wrapper
def collect():"""收藏页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入收藏页面!")@wrapper
def off():global login_informationlogin_information["username"] = Nonelogin_information["status"] = Falselogin_information["count"] = 0print("账户注销成功!")def drop():global flagflag = 0print("欢迎下次光临")func_information = {'1': login, '2': registration, '3': article, '4': comment, '5': diary, '6': collect,'7': off, '8': drop}
while flag:print(msg)choose = input("请选择数字使用对应功能选项:")if choose in func_information:ret = func_information[choose]ret()else:print("你的输入有误,请重新输入")

此时我们所有文件都写在一个py文件下,如果代码量多且都在一个py文件中,那么对于代码结构不清晰,不规范,运行起来效率也会非常低。所以我们接下来一步一步的修改:

1.软件配置:

我们的博客园系统中出现了多处这样的相对路径,如果我们用户注册表位置发生改变,我们需要一处一处修改,那么我们是否可以统一相同的路径,也就是统一相同的变量,在文件的最上面写一个变量指向userinfo注册表的路径,代码中如果需要这个路径时,直接引用即可。

1729998-20190801174800511-1400295791.png

1729998-20190801174820641-780464943.png

1729998-20190801174827394-264747807.png

userinfo_path = r"E:\Python\week3大作业\userinfo.txt"
# 我们博客园系统中出现的相对路径均用userinfo_path替换即可

2.划分文件:

1729998-20190801174843880-487290551.png

一个小型的博客园系统已经这么多代码了,如果我们开发一个项目,可以想象我们的py文件该有多乱了,我们可以将这些函数进行分类,分文件而治,我们将上述py文件依据功能划分以下几类:

settings.py: 配置文件,就是放置一些项目中需要的静态参数,比如文件路径,数据库配置,软件的默认设置等等(如我们上面提到的用户注册表表文件)

common.py:公共组件文件,这里面放置一些我们常用的公共组件函数,并不是我们核心逻辑的函数,而更像是服务于整个程序中的公用的插件,程序中需要即调用。比如我们程序中的装饰器wrapper,有些函数是需要这个装饰器认证的,但是有一些是不需要这个装饰器认证的,它既是何处需要何处调用即可。比如还有密码加密功能,序列化功能,日志功能等这些功能都可以放在这里。

1729998-20190801174903299-196290235.png

src.py:这个文件主要存放的就是核心逻辑功能,你看你需要进行选择的这些核心功能函数,都应该放在这个文件中。

1729998-20190801174911304-1682250361.png

start.py:项目启动文件。你的项目需要有专门的文件启动,而不是在你的核心逻辑部分进行启动的,有人对这个可能不太理解,我为什么还要设置一个单独的启动文件呢?你看你生活中使用的所有电器基本都一个单独的启动按钮,汽车,热水器,电视,等等等等,那么为什么他们会单独设置一个启动按钮,而不是在一堆线路板或者内部随便找一个地方开启呢? 目的就是放在显眼的位置,方便开启。你想想你的项目这么多py文件,如果src文件也有很多,那么到底哪个文件启动整个项目,你还得一个一个去寻找,太麻烦了,这样我把它单独拿出来,就是方便开启整个项目。

1729998-20190801174921860-213769830.png

除了上面提到的几个py文件,还有几个非常重要的文件,类似于userinfo用户注册表的数据库文件,以及以后将拓展的logging日志文件,此外,随着项目功能的扩展,还会多出许多的用户数据表,个人信息表等等,因此,随着项目的增多,单个文件夹下存放各种py文件看起来已经非常烦乱了,此处便可以引出标准版本的项目目录结构了:

1729998-20190801174930995-186423559.png

按照标准项目目录规范化博客园登录系统:

  1. 配置启动文件:

    import sys   # 导入sys模块
    import os    # 导入os模块
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))   #__file__获取当前文件绝对路径,整体获取blog系统绝对路径
    sys.path.append(BASE_DIR)  # 将blog目录添加到环境变量
    from core.src import run   # 从core文件夹src.py文件导入run函数if __name__ == '__main__':    # 程序启动接口run()
  2. 配置settings.py文件:

    import os   # 导入os模块
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))  # blog系统绝对路径
    userinfo_path = os.path.join(BASE_DIR,'db','userinfo.txt')  # 通过拼接获取用户注册表绝对路径
    com_path = os.path.join(BASE_DIR,'db','com.txt') # 获取评论绝对路径
    msg = """1.请登录
    2.请注册
    3.进入文章页面
    4.进入评论页面
    5.进入日记页面
    6.进入收藏页面
    7.注销账号
    8.退出整个程序
    """
  3. 配置common.py文件:

    from core import src   # 从core文件夹导入src主逻辑模块
    import time # 导入时间模块
    """
    操作认证
    :param f: 操作函数
    :return:
    """def wrapper(f):"""操作认证:param f: 操作函数:return:"""def inner():time.sleep(1)if src.login_information["status"]:   f()else:src.login(f)return inner

调整后新版博客园:

程序启动模块:

import sys
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR)
from core import srcif __name__ == '__main__':src.run()

配置模块:

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
userinfo_path = os.path.join(BASE_DIR,'db','userinfo.txt')
com_path = os.path.join(BASE_DIR,'db','com.txt')
msg = """1.请登录
2.请注册
3.进入文章页面
4.进入评论页面
5.进入日记页面
6.进入收藏页面
7.注销账号
8.退出整个程序
"""

公共组件模块:

from core import src
import time
"""
操作认证
:param f: 操作函数
:return:
"""def wrapper(f):"""操作认证:param f: 操作函数:return:"""def inner():time.sleep(1)if src.login_information["status"]:f()else:src.login(f)return inner

主逻辑模块:

import json,time,os
from conf import settings
from lib import common
print('欢迎使用博客园系统')
flag = 1login_information = {"username": None, "status": False}
def login(func=False):"""登录函数:param func: 函数名默认为False:return: 无返回值"""time.sleep(0.1)user_name = input('请输入你要登录的用户名')pwd = input('请输入登录密码')landing_info = {}global login_informationwith open(settings.userinfo_path, "r", encoding="utf-8")as f1:for line in f1:x = line.strip()[:-2]num = int(line.strip()[-1])name = x.split(':', 1)[0]password = x.split(':', 1)[1]landing_info[name] = [password, num]if user_name in landing_info:count = landing_info[user_name][1] + 1if count == 3:print('你的账号已锁定,请联系管理员解锁')else:while count < 3:if pwd == landing_info[user_name][0]:login_information["username"] = user_namelogin_information["status"] = Trueprint("登录成功")if func:func()breakelse:print(f"你的密码输入错误,剩余次数为{3 - count},请重新键入")pwd = input('请重新输入密码:')landing_info[user_name][1] = count + 1count += 1else:print('你的账户已锁定,请联系管理员处理')with open(settings.userinfo_path, 'r', encoding='utf-8')as f1, open('user.txt', 'w', encoding='utf-8') as f2:f1.seek(0, 0)for i in f1:if i.strip().split(':', 1)[0] == user_name:i = i.strip()content = i[:-1] + "3"f2.write(content + '\n')else:f2.write(i)os.remove('userinfo.txt')os.rename('user.txt', 'userinfo.txt')else:print('你输入的账号不存在,请先去注册')def registration():"""注册函数:return:"""user_info = {}num = 3while num:user_name = input('请输入要注册的用户名:')pwd = input('请输入要注册的密码:')num -= 1lst_name = list(range(65, 91)) + list(range(97, 123))for i in user_name:if (i.isdecimal()== True or ord(i) in lst_name) and 6 <= len(pwd) <= 14:passelse:print('用户名或密码无效,请重新输入')if num == 0:print('注册失败')breakelse:with open(settings.userinfo_path, 'r+', encoding='utf-8')as f:for i in f:i = i.strip()[:-2]k, v = i.split(':')user_info[k] = vif user_name in user_info:print('用户名已存在,请重新输入用户名')if num == 0:print('注册失败')continueelse:f.write(f"\n{user_name}:{pwd}:0")choose = input('你已经注册成功,是否重新注册(重新注册键入1)')if choose == '1':num = 3else:print('注册成功,你可以去嚯嚯了')time.sleep(1)num = 3break@common.wrapper
def article():"""文章页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入文章页面!")@common.wrapper
def comment():"""评论页面:return:"""num = 1global login_informationprint(f"欢迎{login_information['username']}进入评论页面!")with open(settings.com_path,'r',encoding="utf-8") as f:for i in f:s = i.strip()print(json.loads(s))num += 1choose = input("是否评论Y or N")if choose == "Y":com = input("请输入评论:")with open('com','a',encoding="utf-8") as f2:com1 = f"{num}楼 - {login_information['username']}:{com}"f2.write(json.dumps(settings.com_path,ensure_ascii=False)+"\n")@common.wrapper
def diary():"""日记页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入日记页面!")@common.wrapper
def collect():"""收藏页面:return:"""global login_informationprint(f"欢迎{login_information['username']}进入收藏页面!")@common.wrapper
def off():global login_informationlogin_information["username"] = Nonelogin_information["status"] = Falselogin_information["count"] = 0print("账户注销成功!")def drop():global flagflag = 0print("欢迎下次光临")func_information = {'1': login, '2': registration, '3': article, '4': comment, '5': diary, '6': collect,'7': off, '8': drop}
def run():while flag:print(settings.msg)choose = input("请选择数字使用对应功能选项:")if choose in func_information:ret = func_information[choose]ret()else:print("你的输入有误,请重新输入")
run()

README的相关内容

这个我觉得是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。

它需要说明以下几个事项:

  1. 软件定位,软件的基本功能。
  2. 运行代码的方法: 安装环境、启动命令等。
  3. 简要的使用说明。
  4. 代码目录结构说明,更详细点可以说明软件的基本原理。
  5. 常见问题说明。

在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。

转载于:https://www.cnblogs.com/lifangzheng/p/11284247.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3 echarts5 graph关系图谱 点击图例节点消失线不消失重复生成问题

const myChart ref(null);const myCharts ref(null);onMounted(() > {// 这种会导致线仍然存在 重复生成myCharts.value echarts.init(myChart.value);myCharts.value.setOption(option);});return {myChart,myCharts,}; 现象&#xff1a;如下图1 点击图例类目2&#xf…

Vue3 VSCode新建项目报错The template root requires exactly one element.

1.首先我们点击左侧第四个图标插件2.输入框搜索vetur插件3.点击设置图标&#xff0c;再点击扩展设置4.搜素vetur>validation>template&#xff0c;取消vetur>validation>template的勾选 然后就不会报错了

Java生鲜电商平台-电商支付流程架构实战

Java生鲜电商平台-电商支付流程架构实战 说明&#xff1a;我一直秉承的就是接地气的业务架构实战。我的文章都有一个这样的核心。 1. 业务场景 2. 解决问题。 3.代码实现。 4.代码重构。 5.总结与复盘。 6.缺点与防范 一、场景描述 想必大家都曾遇到过这个问题&#xff0c;在电…

vue2项目使用codemirror插件实现代码编辑器功能

1、使用npm安装依赖 npm install --save codemirror 2、在页面中放入如下代码 <template><textarea ref"mycode" class"codesql" v-model"code" style"height:200px;width:600px;"></textarea> </template>…

vue3中websocket用法

1.0 认识 websocket #1.0.1 什么是 websocket 和 http 协议类似&#xff0c;websocket 也是是一个网络通信协议&#xff0c;是用来满足前后端数据通信的。 #1.0.2 websocket 相比于 HTTP 的优势 HTTP 协议&#xff1a;客户端与服务器建立通信连接之后&#xff0c;服务器端只…

Scanner类+Random

引用数据类型的使用 数据类型 变量名 new 数据类型(); 变量名.方法名(); import java.util.Scanner; publicclass ScannerDemo01 { publicstaticvoid main(String[] args) { //创建Scanner引用类型的变量 Scanner sc new Scanner(System.in); //获取数字 System.out.print…

webpack入门进阶调优第一章

1.1何为Webpack webpack是开源的JS模块打包工具 核心功能是解决模块之间的依赖&#xff0c;吧哥哥模块按照特定的规则和顺序组织在一起&#xff0c;最终合并为一个JS文件。这个过程叫模块打包 1.2为何需要Webpack 1.2.1何为模块 在设计程序结构时&#xff0c;更好的组织方…

python类的空间问题及类之间的关系

类的空间问题及类之间的关系 类的空间问题 1.何处可以添加对象属性 class A:def __init__(self,name):self.name namedef func(self,sex):self.sex sexobj A("alex") obj.age 18 # 通过__init__方法添加 print(obj.__dict__) obj1 A("wusir") obj.fun…

麻省理工学生发明 震惊世界

核心提示&#xff1a;在普拉纳夫看来&#xff0c;数字信息以像素的形式被限制在显示屏幕之中。他发明的"第六感装置"震惊全场&#xff0c;让世界为之惊叹。 MIT(麻省理工)印度裔学生Prarnav Mistry的天才发明:“第六感装置” 视频地址&#xff1a;http://v.youku.com…

Java生鲜电商平台-优惠券系统的架构设计与源码解析

Java生鲜电商平台-优惠券系统的架构设计与源码解析 电商后台&#xff1a;实例解读促销系统 电商后台系统包括商品管理系统、采购系统、仓储系统、订单系统、促销系统、维权系统、财务系统、会员系统、权限系统等&#xff0c;各系统之间相互关联、相互依托&#xff0c;为前端的正…

VC 2010下安装OpenCV2.4.4

说明&#xff1a; 安装平台&#xff1a;32位XP&#xff0c;VS2010&#xff1b;OpenCV 2.4.4不支持VC 6.0&#xff1b;网上有很多用CMake编译OpenCV的安装教程&#xff0c;这里建议先不要自己编译&#xff0c;如果使用预编译好的库有问题&#xff0c;再尝试自己编译。希望大家好…

vue3源码中的最长递增子序列

求解最长递增子序列是一道经典的算法题, 多数解法是使用动态规划的思想&#xff0c;算法的时间复杂度是O(); 而Vue.js内部使用的是维基百科提供的一套“贪心二分查找”的算法; 贪心算法的时间复杂度是O(n)&#xff0c;二分查找的时间复杂度是O(logn)&#xff0c;总时间复杂度…

Java编程基础阶段笔记 day04 Java基础语法(下)

​ 面向对象编程 笔记Notes 面向对象三条学习主线 面向过程 VS 面向对象 类和对象 创建对象例子 面向对象的内存分析 类的属性&#xff1a;成员变量 成员变量 VS 局部变量 类的方法 方法的重载 可变个数形参 面向对象&#xff1a;封装性 访问权限修饰符 构造方法&…

汉诺塔递归算法

起源&#xff1a; 汉诺塔&#xff08;又称河内塔&#xff09;问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子…

Java编程基础阶段笔记 day 07 面向对象编程(上)

​ 面向对象编程 笔记Notes 面向对象三条学习主线 面向过程 VS 面向对象 类和对象 创建对象例子 面向对象的内存分析 类的属性&#xff1a;成员变量 成员变量 VS 局部变量 类的方法 方法的重载 可变个数形参 面向对象&#xff1a;封装性 访问权限修饰符 构造方法&…

Vue/Angular中父窗口新开的子窗口关闭的时候刷新父窗口

最近遇到一个项目需求&#xff1a;Angular中父窗口新开的子窗口提交完信息关闭的时候刷新父窗口。 知识点&#xff1a; window.opener 概述 返回打开当前窗口的那个窗口的引用&#xff0c;例如&#xff1a;在window A中打开了window B&#xff0c;B.opener 返回 A. 语法 …

HDU 6631 line symmetric(枚举)

首先能想到的是至少有一对相邻点或者中间间隔一个点的点对满足轴对称&#xff0c;那么接下来只需要枚举剩下的点对是否满足至多移动一个点可以满足要求。 第一种情况&#xff0c;对于所有点对都满足要求&#xff0c;那么Yes。 第二种情况&#xff0c;有一个点不满足要求&#x…

学习数字图像处理经验谈

一、面向应用&#xff1a;层层分解、抓住要点 我们学习数字图像处理的最终目的还是应用&#xff0c;不管是用它来研制产品还是研发项目抑或是研究课题&#xff0c;都要用数字图像处理的理论、方法和技术来解决实际问题。在此过程中&#xff0c;提高效率是非常重要的&#xff0c…

react-router-dom@6获取路由传参

目录 参数获取 1、子路由形式携带 2、问号(?)形式参数 3、事件跳转传参 router/index.tsx import App from "App"; import Home from "pages/Home"; import List from "pages/List"; import Detail from "pages/Detail"; import…

koa洋葱模型

Koa 和 Express 都会使用到中间件 Express的中间件是顺序执行&#xff0c;从第一个中间件执行到最后一个中间件&#xff0c;发出响应如上图 Koa是从第一个中间件开始执行&#xff0c;遇到 next 进入下一个中间件&#xff0c;一直执行到最后一个中间件&#xff0c;在逆序&#x…