python之规范化开发

一、规范化开发

​ 当前我们是将所有的代码都写到了一个py文件中,如果代码量多且都在一个py文件中,那么对于代码结构不清晰,不规范,运行起来效率也会非常低。

  1. 设计项目目录结构

    项目目录结构有以下优点:

    • 可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
    • 可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。

    以博客园系统为例:

其中:

  • 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'
    {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]}
    文件内容:{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']}:
    {user_comment}
    ")
            else:
                f6.write(f"评论区:
    -----------------------------------------
    {dic_status['name']}:
    {user_comment}
    ")
            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文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。它需要说明以下几个事项:

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