zoukankan      html  css  js  c++  java
  • day21 模块与包+软件开发目录规范

    一、导入模块的两种方式

    方式一 import + 模块 导入

    优点:该模块内的名字不会和当前名称空间的名字冲突

    缺点:在使用这个模块下的功能或者名字的时候需要加前缀显得麻烦

    方式二 from + 模块 import 名字(模块中的函数或者变量名或者*(全部导入))

    优点:代码精简,使用模块中功能不需要加前缀

    缺点:容易和当前名称空间的名字混淆

    ps 两种导入都可以在后面as起个别名,看具体需求

    两种方式的导入模块都发生了三件事

    1. 产生了一个模块的名称空间
    2. 运行模块.py代码,讲运行产生的名字都丢到模块的名称空间中

    第三件事就是两者的区别,from是直接把这个名字放在了当前名称空间,但是这个名字指向的值还是在模块中

    #方式一导入模块,两个名称空间的变量互不影响,需要模块前缀的原因
    import text2  #text2中的x=1
    
    x=20
    
    print(text2.x)
    
    #方式二导入模块
    from text2 import x,f2#f2的功能是修改全局的x=2,返回一个x
    print(x) 
    #此时在全局中有一个名字x他的内存地址和text2中的x共同指向text2模块中1的内存地址
    >>>1
    x=3 #x和1的绑定关系解除,和3建立绑定关系
    print(x)
    >>>3
    res = f2() #调用函数f2 获取x,此时获取的是text2中的x=1,将x=2并返回
    print(res)
    >>>2
    print(x)#访问的是当前名称空间的x
    >>>3
    

    二、模块搜索的路径的优先级

    优先级:

    1. 内存(内置模块)
    2. 硬盘:按照sys.path中存放的文件顺序依次查找导入的模块
    import sys
    print(sys.path)
    
    
    ['C:\Users\HZ\PycharmProjects\python实训\笔记', 'C:\Users\HZ\PycharmProjects\python实训', 'C:\Program Files\JetBrains\PyCharm 2019.3.4\plugins\python\helpers\pycharm_display', 'C:\Users\HZ\AppData\Local\Programs\Python\Python37\python37.zip', 'C:\Users\HZ\AppData\Local\Programs\Python\Python37\DLLs', 'C:\Users\HZ\AppData\Local\Programs\Python\Python37\lib', 'C:\Users\HZ\AppData\Local\Programs\Python\Python37', 'C:\Users\HZ\PycharmProjects\python实训\venv', 'C:\Users\HZ\PycharmProjects\python实训\venv\lib\site-packages', 'C:\Users\HZ\PycharmProjects\python实训\venv\lib\site-packages\setuptools-39.1.0-py3.7.egg', 'C:\Users\HZ\PycharmProjects\python实训\venv\lib\site-packages\pip-10.0.1-py3.7.egg', 'C:\Program Files\JetBrains\PyCharm 2019.3.4\plugins\python\helpers\pycharm_matplotlib_backend']
    

    通过实验验证加载顺序

    import sys
    import time
    import text2#此时已经导入内存
    
    text2.say()
    
    time.sleep(5)#我们把text2文件删除
    
    import text2
    
    text2.say()#发现还是能执行,说明加载顺序在内存中优先
    

    可以通过sys.path路径的添加,导入其他文件内的模块

    import sys
    
    #sys.modules查看已经加载到内存的模块,不导入其他模块时加载的都是内置模块
    
    sys.path.append(r"C:UsersHZPycharmProjectspython实训笔记day9")
    
    import day9
    
    print(day9.x)
    

    三、循环导入

    上节课我们讲了函数的递归,循环导入的做法也类似,但是我们在写程序的时候千万不能出现循环导入,如果出现了这样的屎一样的代码,就用以下两种“屎上雕花”

    # 方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
    # 文件:m1.py
    print('正在导入m1')
    
    x='m1'
    
    from m2 import y
    
    # 文件:m2.py
    print('正在导入m2')
    y='m2'
    
    from m1 import x
    
    # 文件:run.py内容如下,执行该文件,可以正常使用
    import m1
    print(m1.x)
    print(m1.y)
    
    # 方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码
    # 文件:m1.py
    print('正在导入m1')
    
    def f1():
        from m2 import y
        print(x,y)
    
    x = 'm1'
    
    # 文件:m2.py
    print('正在导入m2')
    
    def f2():
        from m1 import x
        print(x,y)
    
    y = 'm2'
    
    # 文件:run.py内容如下,执行该文件,可以正常使用
    import m1
    
    m1.f1()
    

    四、区分py文件的两种用途

    py文件有两种用途,一种是作为程序运行,一种是作为模块导入。

    所以每个文件都有可能作为两种用途来使用,我们可以用代码区分

    #foo.py
    ...
    if __name__ == '__main__':
        foo.py被当做脚本执行时运行的代码
    else:
        foo.py被当做模块导入时运行的代码
    

    五、编写一个规范的模板

    我们在编写程序的时候,要知道这个代码不仅是给自己看的也要给别人看的,所有要有可读性和易维护性,我们就要对代码中的一些功能加以解释,通常以一个统一的规范编写

    "The module is used to..." #模块的文档描述
    
    import sys #导入模块
    
    x=1 #定义全局变量,如果非必须,则最好使用局部变量,这样可以提高代码的易维护性,并且可以节省内存提高性能
    
    class Foo: #定义类,并写好类的注释
        'Class Foo is used to...'
        pass
    
    def test(): #定义函数,并写好函数的注释
        'Function test is used to…'
        pass
    
    if __name__ == '__main__': #主程序
        test() #在被当做脚本执行时,执行此处的代码
    

    五、包

    1 什么是包

    包就是一个包含有--init--.py文件的文件夹

    2 为什么要有包

    包的本质是模块的一种形式,包是用来被当做模块导入的

    #1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
    
    #2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模
    

    3 包的相关使用

    1、执行包下的__init__.py文件

    2、产生一个新的名称空间用于存放__init__.py执行过程中产生的名字

    3、在当前执行文件所在的名称空间中得到一个名字pool,该名字指向__init__.py的名称空间,例如pool.xxx和pool.yyy中的xxx和yyy都是来自于pool下的__init__.py,也就是说导入包时并不会导入包下所有的子模块与子包

    导包的两种情景

    3.1 在当前文件内导该文件内的包

    #导入同级目录下包aaa内的f2模块
    #导入包aaa的同时会执行__init__.py文件
    from aaa import f2
    
    f2.func2()
    

    3.2 在当前文件内导该文件外的包

    import sys,os
    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
    
    #导入上层目录下的aaa,我们需要把此时运行的文件的环境变量扩展到上层目录  不然无法找到aaa
    from aaa import f1
    
    f1.func1()
    

    六、软件开发的目录规范

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

    Foo/
    |-- core/
    |   |-- core.py
    |
    |-- api/
    |   |-- api.py
    |
    |-- db/
    |   |-- db_handle.py
    |
    |-- lib/
    |   |-- common.py
    |
    |-- conf/
    |   |-- settings.py
    |
    |-- run.py
    |-- setup.py
    |-- requirements.txt
    |-- README
    

    简要解释一下:

    • core/: 存放业务逻辑相关代码

    • api/: 存放接口文件,接口主要用于为业务逻辑提供数据操作。

    • db/: 存放操作数据库相关文件,主要用于与数据库交互

    • lib/: 存放程序中常用的自定义模块

    • conf/: 存放配置文件

    • run.py: 程序的启动文件,一般放在项目的根目录下,因为在运行时会默认将运行文件所在的文件夹作为sys.path的第一个路径,这样就省去了处理环境变量的步骤

    • setup.py: 安装、部署、打包的脚本。

    • requirements.txt: 存放软件依赖的外部Python包列表。

    • README: 项目说明文件。

    除此之外,有一些方案给出了更加多的内容,比如LICENSE.txt,ChangeLog.txt文件等,主要是在项目需要开源时才会用到,请读者自行查阅。

    关于README的内容,这个应该是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。它需要说明以下几个事项:

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

    一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情,这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

    requirements.txt文件的存在是为了方便开发者维护软件的依赖库。我们需要将开发过程中依赖库的信息添加进该文件中,避免在 setup.py安装依赖时漏掉软件包,同时也方便了使用者明确项目引用了哪些Python包。

    这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python依赖库都装好了,具体格式参照https://pip.readthedocs.io/en/1.1/requirements.html

  • 相关阅读:
    自制编译器 青木峰郎 笔记 Ch5 基于JavaCC的解析器描述
    自制编译器 青木峰郎 笔记 Ch4 基于JavaCC的扫描器的描述
    自制编译器 青木峰郎 笔记 Ch3 词法分析的概要
    自制编译器 青木峰郎 笔记 Ch2 Cb和Cbc
    自制编译器 青木峰郎 笔记 Ch1 开始制作编译器
    POJ 1201 Intervals 差分约束,最短路,RE会报TLE 难度:1 差分约束背景知识需联想证明
    POJ 3276 The Cow Lexicon DP 难度: 0
    POJ 1276 Cash Machine DP 难度: 0
    Java大数练习
    HDU 4344-Mark the Rope-大数素因子分解
  • 原文地址:https://www.cnblogs.com/hz2lxt/p/12587551.html
Copyright © 2011-2022 走看看