一、规范化开发
当前我们是将所有的代码都写到了一个py文件中,如果代码量多且都在一个py文件中,那么对于代码结构不清晰,不规范,运行起来效率也会非常低。
设计项目目录结构
项目目录结构有以下优点:
- 可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
- 可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。
以博客园系统为例:
其中:
start.py:项目启动文件。通常将其存放在bin文件夹下。
import sys import os BASE_PATH = os.path.dirname(os.path.dirname(__file__))#获取父级目录也就是blog的绝对路径 sys.path.append(BASE_PATH)# 将bolg项目的路径添加到sys.path列表中,这样所有在blog目录下的py文件都可以相互调用,无需在反复添加文件路径 from core import src if __name__ == '__main__': # 防止start.py文件作为模块被别人引用 src.run()
settings.py: 配置文件,就是放置一些项目中需要的静态参数,比如文件路径,数据库配置,软件的默认设置等等。通常将其存放到conf文件夹。
import os user_info_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),'db','user_info') # 通过获取父级目录的绝对路径,与user_info文件路径拼接,生成user_info文件的路径,可保证只要在blog文件夹下不管项目文件被保存到什么地方都不影响user_info文件路径的获取
src.py:这个文件主要存放的就是核心逻辑功能,需要进行选择的核心功能函数,都应该放在这个文件中。通常将其存放在core文件夹下。
import os from lib import common # 引用lib文件中的common模块(存放装饰器)通过common.的方式引用 from conf import settings # 引用conf文件中的settings模块(存放user_info路径) dic_status = {'name': None, 'status': False} # 登录状态 def get_user_info(): # 用户名和密码文件 with open(settings.user_info_path, encoding='utf-8') as f1: return {i.strip().split('|')[0]: i.strip().split('|')[1] for i in f1} def login(a=get_user_info): # 登录验证 count = 0 dic = a() while count < 3: user_name = input('请输入用户名:').strip() password = input('请输入密码:').strip() if dic.get(user_name) == password: dic_status['name'] = user_name dic_status['status'] = True return True print('用户名或密码错误,请重新输入') count += 1 return quit() def register(b=get_user_info): # 注册 dic = b() while 1: new_name = input('请输入用户名:').strip() if new_name.isalnum(): if dic.get(new_name) == None: password = input('请输入密码:').strip() if 6 < len(password) < 14: with open(settings.user_info_path, mode='a', encoding='utf-8') as f2: f2.write(f'\n{new_name}|{password}') # 需不需要更改登录状态? dic_status['name'] = new_name dic_status['status'] = True return True print('密码长度应在6~14个字符之间,且不能含有空格') else: print('用户名已存在,请重新输入') else: print('用户名只能含有字母或者数字,不能含有特殊字符') @common.wrapper def article(): # 文章功能 print(f"欢迎{dic_status['name']}进入文章界面") print('''1.直接写入 2.导入md文件''') dic_article = {1: article_w, 2: article_im} user_input1 = int(input('请输入选项:').strip()) dic_article[user_input1]() def article_w(): # 直接写 article_content = input('请输入文件名|文件内容:') title = article_content.split('|', 1) with open(fr"{os.path.dirname(os.path.dirname(__file__))}/article/{title[0]}", mode='w', encoding='utf-8') as f3: # 通过返回其父级目录找到article文件夹,将文章写入此文件夹 f3.write(f"文件名:{title[0]}\n文件内容:{title[1]}") print('文章写入成功') def article_im(): # 导入md article_way = input('请输入文件路径:').strip() with open(article_way, encoding='utf-8') as f4, \ open(fr'{os.path.dirname(os.path.dirname(__file__))}/article/函数的进阶.text', mode='w', encoding='utf-8') as f5: for i in f4: f5.write(i) print('导入成功') @common.wrapper def comment(): print(f"欢迎{dic_status['name']}进入评论界面") lis = os.listdir(fr'{os.path.dirname(os.path.dirname(__file__))}/article') for i in range(len(lis)): print(f'{i + 1}.{lis[i]}') user_input = int(input('请输入要评论的文章序号:')) li1 = ["苍老师", "东京热", "武藤兰", "波多野结衣"] with open(fr'{os.path.dirname(os.path.dirname(__file__))}/article/{lis[user_input - 1]}', mode='r+', encoding='utf-8') as f6: c = False for i in f6: print(i) if i == '评论区:': c = True # 判断有没有'评论区' user_comment = input('请输入评论内容:') for el in li1: if el in user_comment: user_comment = user_comment.replace(el, '*' * len(el)) if c: f6.write(f"{dic_status['name']}:\n{user_comment}\n") else: f6.write(f"评论区:\n-----------------------------------------\n{dic_status['name']}:\n{user_comment}\n") print('评论成功') @common.wrapper def diary(): print(f"欢迎{dic_status['name']}进入日记界面") @common.wrapper def collect(): print(f"欢迎{dic_status['name']}进入收藏界面") @common.wrapper def logout(): dic_status['name'] = None dic_status['status'] = False def quit_(): quit() def run(): while 1: print('''1.请登录 2.请注册 3.进入文章页面 4.进入评论页面 5.进入日记页面 6.进入收藏页面 7.注销账号 8.退出整个程序''') dic = {'1': login, '2': register, '3': article, '4': comment, '5': diary, '6': collect, '7': logout, '8': quit_} user_input = input("请输入选项:").strip() if user_input.isnumeric() and 0 < int(user_input) < 9: dic[user_input]() else: print('您输入的序号有误,请重新输入')
common.py:公共组件文件,这里面放置一些常用的公共组件函数,并不是核心逻辑的函数,而更像是服务于整个程序中的公用的插件,程序中需要即调用。比如装饰器,有些函数是需要这个装饰器认证的,但是有一些是不需要这个装饰器认证的,何处需要何处调用即可。比如还有密码加密功能,序列化功能,日志功能等这些功能都可以放在这里。通常将其存放在lib文件夹。
from core import src def wrapper(f): def inner(*args, **kwargs): if src.dic_status['status']: ret = f(*args, **kwargs) return ret else: src.login() ret = f(*args, **kwargs) return ret return inner
类似于user_info文件:这个文件文件名不固定,user_info只是此项目中用到的注册表,但是这种文件就是存储数据的文件,类似于文本数据库。有时会遇到将一些数据存储在文件中,与程序交互的情况,所以要单独设置这样的文件。通常将其存放在db文件夹中。
log文件:log文件顾名思义就是存储log日志的文件。日志主要是供开发人员使用。比如项目中出现一些bug问题,比如开发人员对服务器做的一些操作都会记录到日志中,以便开发者浏览,查询。
README文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。它需要说明以下几个事项:
- 软件定位,软件的基本功能。
- 运行代码的方法: 安装环境、启动命令等。
- 简要的使用说明。
- 代码目录结构说明,更详细点可以说明软件的基本原理。
- 常见问题说明。