zoukankan      html  css  js  c++  java
  • 14.模块的分类,模块的使用,模块的搜索路径优先级,软件开发的目录规范

    • 引子

    • 模块的分类

    • 模块的使用

    • import
    • from...import...
    • 循环导入问题
    • 模块的搜索路径优先级

    • 软件开发的目录规范


    • 模块介绍

    • 1.什么是模块?

      模块就是一系列功能的集合体

      模块大致分为四种类别:

      1、一个py文件就是一个模块,文件名叫test.py,模块名叫test

      2、一个包还有_init_.py文件的文件夹称之为包,包也是模块

      3、使用C编写并连接到python解释器的内置模块

      4、已被编译为共享库或DLL的C或C++扩展

      模块有三种来源:

      1、自带的模块(①直接在python解释器内部的,②标准库:下载python解释器就有的py文件)

      2、第三方模块(下载第三方库:pip3 install requests)

      3、自定义的模块

    • 2.为何要用模块

      1、(自带的模块,第三方模块)->拿来主义,提升开发效率
      2、自定义模块->是为了解决代码冗余问题
    • 3.如何用模块

      模块都是用来被导入使用的,而不是直接运行

    以spam.py为例来介绍模块的使用:文件名spam.py,模块名spam

    # spam.py 被导入的模块
    
    
    print('from the spam.py')
    
    money=1000
    
    def read1():
        print('spam模块:',money)
    
    def read2():
        print('spam模块')
        read1()
    
    def change():
        global money
        money=0
    
    • 使用模块之import

    # run.py    执行spam.py的模块
    
    print('------>')
    
    # 首次导入模块发生的事情
    # 1、运行spam.py,创建一个模块的名称空间,将spam.py运行过程中产生的名字都丢到模块的名称空间中
    # 2、在当前名称空间中得到一个名字,该名字是指向模块的名称空间
    
    import spam    # 后面跟模块名不要跟.py,该模块名指向的是spam.py的名称空间
    import spam    # 后续导入不会执行
    import spam
    # ps: 后续的导入直接引用首次导入的成功,不会重复执行spam.py、不会重复创建名称空间
    
    print(spam.money)  # 指名道姓向spam.py调money
    print(spam.read1)
    print(spam.read2)
    print(spam.change)
    
    money = 2000   
    spam.read1()  # spam模块: 1000   名称空间的关系是在定义阶段确立的与调用无关   
    
    def read1():
        print('xxx')
    
    spam.read2()  # spam模块: 1000
    
    
    money = 2000
    spam.change()
    print(money)
    print(spam.money)
    
    
    # 3、导入规范
    # 通常情况下所有的导入语句都应该写在文件的开头,然后分为三部分:
    # 第一部分:先导入自带的模块
    # 第二部分:导入第三方
    # 第三部分:导入自定义的
    
    # 4、import的其他用法
    import os,sys,re   # 在一行一次导入多个模块(不建议使用)
    import spam as sm  # 为模块起别名
    print(sm.money)
    
    
    money = 2000
    print(spam.money)  # 1000  # 加spam.前缀,名字不会与当前名称空间名字冲突,每次调用都需要加前缀
    print(money)  # 2000 没加前缀就是向当前名称空间调用
    
    

    from...import... 与import的对比

    # 唯一的区别就是:使用from...import...则是将spam中的名字直接导入到当前的名称空间中
    # 所以在当前名称空间中,直接使用名字就可以了、无需加前缀:spam.
    
    # import 
    #    好处:加前缀不会与当前执行文件的名称空间名字冲突
    #    坏处:加前缀使用起来麻烦
    
    # from...import...的方式有好处也有坏处
    #    好处:使用起来方便了
    #    坏处:容易与当前执行文件的名称空间名字冲突
    
    • 使用模块之from...import...

    # run.py  执行spam.的模块
    
    print('------>')
    
    # 首次导入模块发生的事情
    # 1、运行spam.py,创建一个模块的名称空间,将spam.py运行过程中产生的名字都丢到模块的名称空间中
    # 2、在当前名称空间中得到一个名字money,该名字是指向模块的名称空间的那个money
    from spam import money  
    from spam import money  # 后续导入不会执行
    from spam import money
    from spam import read1
    # ps: 后续的导入直接引用首次导入的成功,不会重复执行spam.py、不会重复创建名称空间
    
    money = 2000
    print(money)  # 2000  money与当前名称空间名字冲突,会互相覆盖
    
    money = 2000
    read1()      # spam模块:1000 先确定read1()来自于哪,以来的地方为准找作用域关系
    
    
    money = 2000
    def read1():
        print('xxxx',money)
    
    read1() # xxxx 2000  # 此时read1()找的是当前名称空间
    
    
    # 其他用法
    from spam import money,read1,read2,change  # 一行导入多个名字
    from spam import money as m,read1 as r1,read2 as r2,change # 也支持as,为模块起别名
    print(m)
    print(r1)
    print(r2)
    
    # from...import*
    from spam import *  # 把spam中所有的不是以下划线开头的名字都导入到当前位置
    # print(money)
    # print(read1)
    print(read2)
    print(change)
    # 大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有
    # 可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。
    
    • 模块循环导入问题

    模块循环导入抛出异常的根本原因是由于在python中模块被导入一次之后,就不会重新导入,只会在第一次导入时执行模块内代码

    在我们的项目中应该尽量避免出现循环导入,如果出现多个模块都需要共享的数据,可以将共享的数据集中存放到某一个地方

    • 模块搜索路径与优先级

      1、内存中已经导入好的

      2、内置

      3、sys.path

    # 内存---》内置---》sys.path
    
    # 1.内存:在第一次导入某个模块时(比如spam),会先检查该模块是否已经被加载到内存中
    #     (当前执行文件的名称空间对应的内存),如果有则直接引用
    # ps:python解释器在启动时会自动加载一些模块到内存中,可以使用sys.modules查看
    import m1   # 导入m1模块
    import time
    
    m1.f1()
    time.sleep(5)  # 在五秒内删除m1并执行当前模块仍能调取m1 过完5秒再执行就出现报错,说明优先从内存找
    import m1
    m1.f1()
    
    # 2.内置:如果内存没有,python解释器则会查找同名的内置模块
    import time,os
    
    print(time)  # <module 'time' (built-in)>
    print(os)    # <module 'os' from 'D:\Python38\lib\os.py'>
     
    
    # 3.sys.path:如果内置还没有找到就从sys.path给出的目录列表中依次寻找spam.py文件
    import sys
    print(sys.path)
    
    import m1
    m1.f1()
    
    import aaa.m1 as m
    aaa.m1.f1()
    m.f1()
    
    # 需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。 
    
    # 在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载
    import sys
    print(sys.path)
    sys.path.append(r'D:python17day02') # windows下的路径不加r开头,会语法错误
    
    import m2
    m2.f2()
    
    
    sys.path.append(r'D:python17')
    import day02.m2  # D:python17day02m2
    day02.m2.f2()
    
    import time
    time.sleep(3)
    
    • 软件开发的目录规范

    core文件夹: 存放源文件,业务逻辑相关代码
    api文件夹: 存放接口文件,接口主要用于为业务逻辑提供数据操作。  
    db文件夹: 存放数据库文件,主要用于与数据库交互   
    lib文件夹: 存放程序模块,库,第三方代码
    conf文件夹: 存放配置文件相关代码件
    log:存放日志访问文件记录
    start.py: 程序的启动文件,一般放在项目的根目录下,因为在运行时会默认将运行文件所在
        	  的文件夹作为sys.path的第一个路径,这样就省去了处理环境变量的步骤    
    Readme: 项目说明文件。
    
    

  • 相关阅读:
    【来自知乎】AR技术可以通过H5实现吗?不通过APP
    太虚AR
    【ArUco】- Augmented reality library based on OpenCV
    unity MVC简易框架! MVC in Code Control
    游戏服务器框架与互联网产品的认识
    关于 boost::asio::io_service::run() 出现【句柄无效】的问题
    编译luabind-0.9.1 出现 error C2665: 'boost::operator ==' : none of the 4 overloads could convert all the argument types 的解决方案
    javascript 控制 table tr display block 显示模式时,只对第一个单元格有效
    Ogre::UINT 与 其他库的 类型冲突问题
    排序仿函数 出现 std::priority_queue::push() 的 invalid operator < 异常
  • 原文地址:https://www.cnblogs.com/gfeng/p/14233181.html
Copyright © 2011-2022 走看看