当前位置: 首页 > news >正文

Python(八)—— 开发

18. 软件开发规范

软件开发,规范你的项目目录结构,代码规范,遵循PEP8规范等等,让你更加清晰合理开发

例如下面这个yuluoCSDN.py文件,是一个雨落CSDN网页的登录页面,包含登录、注册等多个功能,全部写到一个文件里,此时我们阅读起来就会觉得代码结构不清晰也不规范,运行起来效率也会非常低

status_dic = {
    'username': None,
    'status': False,
}
flag = True


def login():
    i = 0
    with open('register', encoding='utf-8') as f1:
        dic = {i.strip().split('|')[0]: i.strip().split('|')[1] for i in f1}
    while i < 3:
        username = input('请输入用户名:').strip()
        password = input('请输入密码:').strip()
        if username in dic and dic[username] == password:
            print('登录成功')
            return True
        else:
            print('用户名密码错误,请重新登录')
            i += 1


def register():
    with open('register', encoding='utf-8') as f1:
        dic = {i.strip().split('|')[0]: i.strip().split('|')[1] for i in f1}
    while 1:
        print('\033[1;45m 欢迎来到注册页面 \033[0m')
        username = input('请输入用户名:').strip()
        if not username.isalnum():
            print('\033[1;31;0m 用户名有非法字符,请重新输入 \033[0m')
            continue
        if username in dic:
            print('\033[1;31;0m 用户名已经存在,请重新输入 \033[0m')
            continue
        password = input('请输入密码:').strip()
        if 6 <= len(password) <= 14:
            with open('register', encoding='utf-8', mode='a') as f1:
                f1.write(f'\n{username}|{password}')
            status_dic['username'] = str(username)
            status_dic['status'] = True
            print('\033[1;32;0m 恭喜您,注册成功!已帮您成功登录~ \033[0m')
            return True
        else:
            print('\033[1;31;0m 密码长度超出范围,请重新输入 \033[0m')


def auth(func):
    def inner(*args, **kwargs):
        if status_dic['status']:
            ret = func(*args, **kwargs)
            return ret
        else:
            print('\033[1;31;0m 请先进行登录 \033[0m')
            if login():
                ret = func(*args, **kwargs)
                return ret

    return inner


@auth
def article():
    print(f'\033[1;32;0m 欢迎{status_dic["username"]}访问文章页面\033[0m')


@auth
def diary():
    print(f'\033[1;32;0m 欢迎{status_dic["username"]}访问日记页面\033[0m')


@auth
def comment():
    print(f'\033[1;32;0m 欢迎{status_dic["username"]}访问评论页面\033[0m')


@auth
def enshrine():
    print(f'\033[1;32;0m 欢迎{status_dic["username"]}访问收藏页面\033[0m')


def login_out():
    status_dic['username'] = None
    status_dic['status'] = False
    print('\033[1;32;0m 注销成功 \033[0m')


def exit_program():
    global flag
    flag = False
    return flag


choice_dict = {
    1: login,
    2: register,
    3: article,
    4: diary,
    5: comment,
    6: enshrine,
    7: login_out,
    8: exit_program,
}

while flag:
    print('''
    欢迎来到雨落的CSDN首页
    1:请登录
    2:请注册
    3:文章页面
    4:日记页面
    5:评论页面
    6:收藏页面
    7:注销
    8:退出程序''')

    choice = input('请输入您选择的序号:').strip()
    if choice.isdigit():
        choice = int(choice)
        if 0 < choice <= len(choice_dict):
            choice_dict[choice]()
        else:
            print('\033[1;31;0m 您输入的超出范围,请重新输入 \033[0m')

    else:
        print('\033[1;31;0m 您您输入的选项有非法字符,请重新输入 \033[0m')

18.1 程序配置

def login():
    i = 0
    with open('register', encoding='utf-8') as f1:
        dic = {i.strip().split('|')[0]: i.strip().split('|')[1] for i in f1}
def register():
    with open('register', encoding='utf-8') as f1:
        dic = {i.strip().split('|')[0]: i.strip().split('|')[1] for i in f1}
if 6 <= len(password) <= 14:
    with open('register', encoding='utf-8', mode='a') as f1:
        f1.write(f'\n{username}|{password}')

上面这个项目中所有的有关文件的操作出现几处,都是直接写的register相对路径,如果说这个register注册表路径改变了,或者你改变了register注册表的名称,那么相应的这几处都需要一一更改,这样其实你就是把代码写死了

那么这时就要统一相同的路径,也就是统一相同的变量,在文件的最上面写一个变量指向register注册表的路径,代码中如果需要这个路径时,直接引用即可

18.2 划分文件

一个具体的实际的项目,函数会非常多,所以我们应该将这些函数进行分类,然后分文件而治。在这里划分了以下几个文件:

1、settings.py:配置文件,就是放置一些项目中需要的静态参数,比如文件路径,数据库配置,软件的默认设置等

register_path = r'C:/Users/yuluo/PycharmProjects/雨落-Python/雨落教学/yuluoCSDN.py'

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

def auth(func):
    def inner(*args, **kwargs):
        if status_dic['status']:
            ret = func(*args, **kwargs)
            return ret
        else:
            print('\033[1;31;0m 请先进行登录 \033[0m')
            if login():
                ret = func(*args, **kwargs)
                return ret

    return inner

3、src.py:这个文件主要存放的就是核心逻辑功能,这些核心功能函数,都应该放在这个文件中

def login():
    pass

def register():
    pass

@auth
def article():
    pass

@auth
def diary():
    pass

@auth
def comment():
    pass

@auth
def enshrine():
    pass

def login_out():
    pass

def exit_program():
    pass

4、start.py:项目启动文件。你的项目需要有专门的文件启动,而不是在你的核心逻辑部分进行启动的,目的就是放在显眼的位置,方便开启

while flag:
    print('''
    欢迎来到雨落的CSDN首页
    1:请登录
    2:请注册
    3:文章页面
    4:日记页面
    5:评论页面
    6:收藏页面
    7:注销
    8:退出程序''')

    choice = input('请输入您选择的序号:').strip()
    if choice.isdigit():
        choice = int(choice)
        if 0 < choice <= len(choice_dict):
            choice_dict[choice]()
        else:
            print('\033[1;31;0m 您输入的超出范围,请重新输入 \033[0m')

    else:
        print('\033[1;31;0m 您您输入的选项有非法字符,请重新输入 \033[0m')

但是上面这个文件,看起来还是有些吃操作,那有没有更方便的呢,有的有的兄弟,像这样更方便的那就是整合成函数,一键启动,这个 run() 就是整个文件的开关

def run():
    while flag:
        print('''
        欢迎来到雨落的CSDN首页
        1:请登录
        2:请注册
        3:文章页面
        4:日记页面
        5:评论页面
        6:收藏页面
        7:注销
        8:退出程序''')
    
        choice = input('请输入您选择的序号:').strip()
        if choice.isdigit():
            choice = int(choice)
            if 0 < choice <= len(choice_dict):
                choice_dict[choice]()
            else:
                print('\033[1;31;0m 您输入的超出范围,请重新输入 \033[0m')
    
        else:
            print('\033[1;31;0m 您您输入的选项有非法字符,请重新输入 \033[0m')

run()

5、类似于register文件:这个文件文件名不固定,register只是我们项目中用到的注册表,但是这种文件就是存储数据的文件,类似于文本数据库,那么我们一些项目中的数据有的是从数据库中获取的,有些数据就是这种文本数据库中获取的,总之,你的项目中有时会遇到将一些数据存储在文件中,与程序交互的情况,所以我们要单独设置这样的文件

6、log文件:log文件顾名思义就是存储log日志的文件。日志主要是供开发人员使用,比如你项目中出现一些bug问题,比如开发人员对服务器做的一些操作都会记录到日志中,以便开发者浏览,查询

至此我们合理的划分成了6个文件,但是还是有问题的,如果我们的项目很大,每一个部分相应的一个文件存不下的,比如src主逻辑文件,函数很多,是不是得分成:src1.py、src2.py;而且文本数据库register这个只是一个注册表,如果还有个人信息表,记录表呢? 如果是这样,我们还需划分目录

18.3 划分具体目录

规范化能更好的控制程序结构,让程序具有更高的可读性;我们设计一个层次清晰的目录结构,就是为了达到以下两点:

1、可读性高:不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目

2、可维护性高:定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好

目录结构:

1、bin文件夹下对应start.py
2、conf文件夹下对应settings.py

3、core文件夹下对应src.py
4、db文件夹下对应register (txt)
5、lib文件夹下对应common.py
6、log文件夹下对应access.log (txt)
7、此外应该还包含README

关于README:

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

在软件开发初期,由于开发过程中内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的,目的是能简要描述该项目的信息,让读者快速了解这个项目。可以参考Redis源码中Readme的写法,这里面简洁但是清晰的描述了Redis功能和源码结构

18.4 包

18.4.1 包的定义

  • 包是一种通过使用 .模块名 来组织python模块名称空间的方式

  • 具体的:包就是一个包含有 __init__.py 文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来

  • 需要强调的是:

    • 1、在python3中,即使包下没有 __init__.py 文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

    • 2、创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块

  • 为何要使用包

    包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来。随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性

18.4.2 注意事项

  • 1、关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包、模块、函数、类(它们都可以用点的方式调用自己的属性)

  • 2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的 __init__.py ,导入包本质就是在导入该文件

  • 3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

未写完,待续……

相关文章:

  • 显示器各类异常处理方法
  • [ctfshow web入门] web30
  • Qt子模块的功能介绍
  • Python星球日记 - 第15天:综合复习(回顾前14天所学知识)
  • git命令自动拉去远程分支到本地
  • 基于RoboTwin的数据训练RDT开源VLA模型
  • 牛客华为机试--HJ48 从单向链表中删除指定值的节点C++
  • 典型反模式深度解析及重构方案
  • 什么是 Git?为什么要用版本控制?
  • Python爬虫第三战(使用session登录小说网获取书单)
  • 蓝桥备赛指南(14):树的直径与重心
  • 判断矩阵A和矩阵B是否相似?
  • 解决使用PendingIntent.getBroadcast时出现java.lang.IllegalArgumentException异常的问题
  • (四十)Dart 中的空安全(Null Safety)教程
  • Web品质 - 重要的HTML元素
  • Linux 命令清单(Linux Command List)
  • MySQL随机获取记录之方法(The Method of Randomly Obtaining Records in MySQL)
  • 【python3】关于等额本金和等额本息计算
  • Activiti(二)- 基于SpringBoot开发配置activiti相关配置项
  • 深入理解C++面向对象特性之一 多态
  • 河南:响鼓重锤对违规吃喝问题露头就打、反复敲打、人人喊打
  • 上海黄浦江挡潮闸工程建设指挥部成立,组成人员名单公布
  • 中日东三省问题的源起——《1905年东三省事宜谈判笔记》解题
  • 著名植物学家、园艺学家,国际植物园协会原主席贺善安逝世
  • 美国和沙特签署上千亿美元军售协议
  • 图讯丨习近平出席中国-拉美和加勒比国家共同体论坛第四届部长级会议开幕式