• 模块与包管理


    模块

    """
    常见的四种模块:module
    1.使用python编写的.py文件
    2.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
    3.使用C编写并链接到python解释器的内置模块
    4.已被编译为共享库或DLL的C或C++扩展
    """
    
    # 1、什么是模块:一系列功能的集合体,模块都有'.'语法
    任何一个py文件或者说数据结构都能称为模块,因为都有'.'语法
    
    # 2、为什么会出现模块:很多相似的功能,要统一管理,将这些功能放在一个文件中,该文件就是管理这些功能的集合体,我们命名为模块
    
    # 3、怎么使用模块
    #		-- 在要使用模块功能的文件中导入模块:
    import 模块名  - 模块名:用来管理一系列功能的文件名(实现功能的文件名)
    
    # 4、在哪使用模块
    #		-- 在所有要使用模块中功能的文件中导入并使用模块
    
    #模块文件(m1.py)
    def f1():
        print('扫地')
    
    def f2():
        print('洗衣')
    
    def f3():
        print('拖地')
        
    # 使用模块文件
    import m1
    
    m1.f1()
    m1.f2()
    m1.f3()
    
    

    导入模板完成的三件事

    # 首次导入
    import 模块名
    
    # 1.将被导入的模块编译形成对应的pyc文件
    # 2.进入模块,从上至下执行模块中的代码,将产生的所有名字(变量)存放在该模块文件的全局名称空间中
    # 3.在使用模块的文件中,产生一个与模块名(模块文件名)同名的名字(变量),指向模块的全局名称空间,这个名字可以称为文件对象或者模块对象
    
    #文件对象/模块对象
    代表模块,指向的是模块文件里存储对象的名称空间的地址,通过使用'.'语法去使用模块里的东西
    
    # 模块文件 m1.py
    print(1)
    print(2)
    print(3)
    a=10
    
    def fn():
        print(a)
    print('end')
    
    #使用模块的文件
    import m1
    print(m1.__dict__)  #打印m1的名称空间
    print(m1.__dict__['a'])  #打印m1的名称空间
    print(m1.a)  # m1文件对象通过'.'语法去使用模块里的变量a
    print('t1 end')
    
    print(m1)  #打印的是m1这个文件对象指向的模块的地址
    
    
    # 再次导入
    
    # 不再执行导入模块的前两步,只会走第三步:在当前模块中产生一个名字,指向第一次导入在内存中产生的全局名称空间
    
    import m1
    print(m1.a)
    print(m1.__dict__)  #再次导入模块m1, m1的地址指向模块的名称空间
    

    起别名

    import 模块名 as 别名
    
    # 重点:导入一旦起别名,原模块名变量失效,本质只产生了别名变量指向模块文件的全局名称空间
    

    模块的分类

    # 大方向:内置(built-in) | 自定义(系统提供 | 第三方提供 | 自己自定义)
    

    模块的加载顺序

    # 内存 > 内置 > sys.path (安装环境变量中路径的先后顺序逐一加载)
    
    # 自定义模块加载顺序: 根据环境变量中路径的顺序依次执行,加载到了就停止,所以排在前面的路径下的自定义模块先加载
    

    环境变量

    存放路径的list,第一位默认一定是当前执行文件所在的路径

    #举例
    
    >>> part4/t1.py
    import sys
    print(sys)
    print(sys.path)
    # ['/Users/cj/Desktop/pycharm_project_2/part4', '/Users/cj/Desktop/pycharm_project_2', '/Applications/PyCharm.app/Contents/helpers/pycharm_display', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Applications/PyCharm.app/Contents/helpers/pycharm_matplotlib_backend']
    
    >>> part3/t1.py
    import sys
    print(sys)
    print(sys.path)
    # ['/Users/cj/Desktop/pycharm_project_2/part3', '/Users/cj/Desktop/pycharm_project_2', '/Applications/PyCharm.app/Contents/helpers/pycharm_display', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Applications/PyCharm.app/Contents/helpers/pycharm_matplotlib_backend']
    
    import sys
    # sys.path就是环境变量
    
    # 清空环境变量:所有导入都不能使用了
    sys.path.clear()
    
    # 添加指定路径到环境变量
    sys.path.append()
    sys.path.insert()
    

    from...import语法导入

    # 导入完成的三件事
    # 1.将被导入的模块编译形成对应的pyc文件
    # 2.进入模块,从上执行执行模块中的代码,将产生的所有名字存放在该模块文件的全局名称空间中
    # 3.在导入模块的文件中形成(一个或多个)名字指向模块全局名称空间中的(一个或多个)具体名字
    
    from 模块名 import 模块中的名字1, ..., 模块中的名字n
    from 模块名 import 名字 as 别名
    
    
    # from...import导入依赖环境变量 sys.path
    
    #添加环境变量
    import sys
    sys.path.append(r'/Users/cj/Desktop/pycharm_project_2/part2/t1.py')
    

    from...import *

    # 模块中默认会添加 __all__ ,__all__ 就是管理模块中能被 * 导入的变量们
    # __all__可以自定义,自定义 * 能导入的变量们, __all__的list中名字全部可以自定义
    __all__ = ['a', 'b', 'c', 'd_', '_e']
    
    
    # 系统默认添加的__all__中不会纳入 _开头的名字
    #       -- 所以默认在外界通过from...import *无法导入_开头的名字
    #		-- _开头的名字对from...import *是隐藏的,指名道姓依然可以被外界导入使用
    
    
    #m1.py
    _c=2
    a=1000
    
    #t1.py
    from m1 import *
    print(a)
    print(_c) #报错 NameError: name '_c' is not defined
    
    #m1.py
    _c=2
    a=1000
    
    #t1.py
    from m1 import _c
    print(_c) #输出c的值
    

    链式导入

    # t1导入m1,m1导入m2,m2导入m3
    
    # 执行流程:右键执行t1,在t1导入m1模块的地方直接进入m1,去执行m1,同理在m1执行过程中遇到导入m2,会马上进入m2,去执行m2,一直到m3,m3执行完毕,会回到m2中导入m3的语句,接着往下执行m2,m2执行完毕回到m1,以此类推返回到t1
    
    # 在整个执行流程中,遇到任何模块的二次导入,都是直接引用内存中的名称空间,不会再次进入模块
    
    #t1.py
    print('t1 start')
    
    import m1
    print('t1 end')
    
    #m1.py
    print('m1 start')
    
    import m2
    print('m1 end')
    
    #m2.py
    print('m2 start')
    
    import m3
    print('m2 end')
    
    #m3.py
    print('m3 start')
    import m1
    import m2
    
    print('m3 end')
    

    循环导入

    # 循环导入的问题点:名字没有产生就使用名字
    # 解决循环导入:先产生名字,在导入模块
    #       -- 将会产生循环导入的模块,导入语法延后 - 延后导入
    
    
    # 问题
    #t1.py
    import m1
    
    # m1.py
    import m2
    print(m2.y)
    x=666
    
    # m2.py
    import m1
    print(m1.x)
    y=888
    
    
    
    # 解决
    #t1.py
    import m1
    
    # m1.py
    x=666
    import m2
    print(m2.y)
    
    # m2.py
    import m1
    y=888
    print(m1.x)
    

    sys.path显示

    # 在pycharm中,sys.path环境变量这个列表索引0号位显示的是当前文件所在的路径,索引1号位显示的是pycharm中的项目的根目录
    
    import sys
    print(sys.path[0])  # /Users/cj/Desktop/pycharm_project_3/part1/b/c
    print(sys.path[1]) # /Users/cj/Desktop/pycharm_project_3
    
    # 但是在命令行界面,sys.path并不会显示项目的根目录
    cj@cjwdeMacBook-Pro pycharm_project_3$ python3 /Users/cj/Desktop/pycharm_project_3/part1/t1.py
    ['/Users/cj/Desktop/pycharm_project_3/part1', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']
    

    跨文件导入模块分析

    # 需求:跨文件夹访问
    #目录结构
    part1 
    -> t1.py
    ->a(ma.py)
    ->b->c(mc.py)
    
    #打开pycharm时,当前执行文件的环境变量是会被自动创建为这个文件所在的目录,所以如果import 该文件所在的目录的任意模块文件都是可以的
    
    #有时候我们要导入当前文件所在的目录的同级目录的模块文件,或者是同级目录以下的模块文件,这个时候可以将路径加入环境变量或者通过'.'语法进行层级导入,这本质上就是一个绝对路径,起始路径是从环境变量中定义的路径开始的,如果后面需要print输出这个值,那么后面也是要写除了环境变量定义的路径外的所有路径,这种情况定义别名更方便
    
    (方法一) 绝对导入(将文件所在的目录的路径拷贝到环境变量sys.path)
    import sys
    
    # 访问模块文件ma里的变量aaa
    sys.path.append(r'/Users/cj/Desktop/pycharm_project_3/part1/a')
    import ma
    print(ma.aaa)
    
    # 访问模块文件mc里的变量ccc
    sys.path.append(r'/Users/cj/Desktop/pycharm_project_3/part1/b/c')
    import mc
    print(mc.ccc)
    
    方法(二) 导入时写绝对路径
    
    # 访问模块文件ma里的变量aaa
    import a.ma
    print(a.ma.aaa)
    
    # 访问模块文件mc里的变量ccc
    import b.c.mc
    print(b.c.mc.ccc)
    
    方法(三)通过from...import 直接访问到模块里的变量,基于方法二
    # 访问模块文件ma里的变量aaa
    from a.ma import aaa
    print(aaa)
    
    # 访问模块文件mc里的变量ccc
    from b.c.mc import ccc
    print(ccc)
    
    #报错信息 ('.'左侧为文件)
    import a.ma.aaa  #语法错误
    ModuleNotFoundError: No module named 'a.ma.aaa'; 'a.ma' is not a package
    
    #报错信息 ('.'左侧为文件)
    from b.c import mc.ccc as ccc  #语法错误
    SyntaxError: invalid syntax   
      
    #结论: 
    导模块中的'.'语法左侧必须为文件夹
    import 后面最后只能导入到文件,可以是import <文件夹>.<文件>,但是不能是import <文件>.<文件>
    from...import 中的import后面可以导入文件中的具体名字(变量名/函数名)
    

    跨文件夹导入模块总结

    # 1.如果a文件夹所在目录在环境变量,a文件夹中的ma模块可以被以下方式导入
    import a.ma  |  from a import ma 
    
    # 2.如果a文件夹所在目录在环境变量,a文件夹中的b文件夹的mb模块可以被以下方式导入
    import a.b.mb  |  from a.b import mb
    
    # 3.如果a文件夹所在目录在环境变量,a文件夹中的b文件夹的mb模块中的bbb名字要被直接导入 
    import a.b.mb.bbb  # 错误:所有.左侧必须是文件夹 *****
    from a.b import mb.bbb # 错误:所有.左侧必须是文件夹
    from a.b.mb import bbb # 正确
    

    模块的两种被执行方式

    # 总结: 
    # 1.一个py文件作为自执行文件,__name__变量的值为 '__main__'
    # 2.一个py文件作为模块被导入执行,__name__变量的值为 '文件(模块)名'
    # 3. __name__的值始终是字符串
    # 4. pycharm中直接输入main就能快速出现 if __name__ == '__main__':
    
    # 如何区别两种方式,可以让一个文件可以自执行,也可以被导入执行 共存
    # 在这样的py文件中写:
    if __name__ == '__main__':
        # 自执行的逻辑 => 因为在文件作为模块使用时 __name__为文件名,不满足条件
        pass
      
    #案例 fn3()函数所在的文件被外部调用时候不执行,外部调用时候只执行2个函数fn1(),fn2()
    # m1.py
    def fn1():
        print('fn1 run')
    
    def fn2():
        print('fn2 run')
    
    def fn3():
        fn1()
        fn2()
        print('fn3 run')
    
    
    if __name__ == '__main__':
        fn3()
        
    #t1.py
    from m1 import fn1,fn2
    fn1()
    fn2()
    

    模块:一系列功能的集合体
    包: 一系列模块的集合体,用文件夹来管理一系列有联系功能的模块
    
    # 包 与 普通文件夹存在区别:包的文件夹中一定存在一个__init__.py文件
    #		-- py2:必须创建  py3:建议创建,不创建系统会自动创建
    
    
    # __init__.py文件
    # 1)产生一个全局名称空间,提供给包的,就代表包的名称空间
    # 2)管理 包可以直接点出来使用的 名字
    
    如果没有__init__文件,在py3中会自动优化生成一个名称空间,存储一些系统的内置变量,但是不会文件夹下面模块里定义的名字(变量名/函数名),py2中则直接报错
    
    #(案例1)
    文件结构:
    part5
    	>mp(m1.py/m2.py)
      >t1.py
    import mp  #如果没有init文件, mp的名称空间是无法产生m1,m2模块以及他们的名字的对应关系
    # 需求: 可以直接通过包名使用包中的某一个模块
    print(mp.m1.a)
    print(mp.m1.b)
    print(mp.m1.c)
    
    # 需求: 可以直接通过包名使用包中的某个模块的名字
    print(mp.x)
    print(mp.y)
    print(mp.z)
    
    # (案例2)
    文件结构:
    part3
    	->mp(m1.py, m2.py, m3.py)
      ->t1.py
    
     (python2 环境中)
    #t1.py
    import mp
    print mp
    
    报错信息:ImportError: No module named mp
    
      (python3 环境中)
      import mp
      print(mp)
      <module 'mp' (namespace)> # mp自己的名称空间为空
      print(mp.__dict__)  # python3自动创建一个名称空间,都是系统内置的变量的对应关系
    
      
    # 导包完成的三件事
    # 1)编译形成包中__init__.py文件的pyc文件
    # 2)执行__init__.py文件,形成一个全局名称空间,将__init__.py文件中所有名字存放其中,该名称空间就代表包的名称空间
    # 3)在导包的文件中,产生一个与包名相同的名字,指向包的名称空间(__init__.py文件的全局名称空间)
    

    相对导入

    需求1 : 可以直接通过包名使用包中的某个模块的名字

    文件结构:
    part3
    	->mp(m1.py, m2.py, m3.py,__init__.py)
      ->t1.py
     
    (方法一) 直接将值存入__init__.py 文件
    #t1.py
     # 可以直接通过包名使用包中的某个模块的名字
    print(mp.x)
    print(mp.y)
    print(mp.z)
    
    # __init__.py
    x=111
    y=222
    z=333
    
    (方法二) 将m1导入__init__.py 文件
    #t1.py
     # 可以直接通过包名使用包中的某个模块的名字
    import mp
    print(mp.m1.a)
    print(mp.m1.b)
    print(mp.m1.b)
    print(mp.m1.c)
    
    # __init__.py
    from . import m1
    
    
    # '.'就是mp
    

    需求2: 可以直接通过包名使用包中的某个模块的名字

    #t1.py
    import mp  # 导入一个绝对路径/Users/cj/Desktop/pycharm_project_3/part5/mp,所以__init__文件中可以使用相对路径,相当于__init__文件中再导入模块都是基于这个路径导入了
    print(mp.x)
    print(mp.y)
    print(mp.z)
    
    # __init__.py
    from .m2 import x
    from .m2 import y
    from .m2 import z
    
    # '.'就是mp
    

    需求3:直接通过包名使用包中子包模块中的名字

    文件结构:
    part3
    	->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py, __init__.py)
      ->t1.py
      # subp/s1.py
      sss=8888
      
      #mp/__init__.py
      from .subp.s1 import sss
      from .subp import s1
      
      #t1.py
      print(mp.sss)
      print(mp.s1.sss)
    

    总结

    1. mp是一个包,下面存着各个模块文件,运行文件中只要是导入了 import mp,则只要是__init__ 文件里面导入的模块,都能使用;
    __init__ 文件中导入模块可以使用相对路径,可以用'.'代替mp
    2. import mp ----> 执行文件下相当于导入一个路径 /Users/cj/Desktop/pycharm_project_3/part5/mp
    所以__init__文件中可以使用相对路径,相当于__init__文件中再导入模块都是基于这个路径导入了
    3. from...import... 格式的文件,后面只能跟一个文件夹或者文件或者名字,不能跟多个字文件夹,文件,名字,用'.'分隔
    
    from . import m1  #正确
    from .m2 import x #正确
    from .m2 import y  #正确
    from . import m2.z  #错误
    

    直接使用包中模块

    # 如果只是想作为普通文件夹,py3中可以省略__init__文件,本质上文件夹也是包
    
    # 导入的手段:1.指名道姓到某一个模块 | 2.指名道姓到某一个模块中的名字
    

    包的管理

    #在包中管理模块,或者模块与模块直接功能相互使用,通过from .开头 import 语法进行导入,这种导入叫相对导入
    # 在包的__init__.py文件或是包中任意一个模块中
    # . 代表当前文件所在目录
    # .. 代表当前文件所在目录的上一级目录
    # 注:.语法不能出包,因为包外的文件都能自执行,但拥有.开头导入的文件不能自执行
    
    
    文件结构:
    part3
    	->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py,s1.py,s3.py __init__.py)
      ->t1.py
      
      # subp/s1.py
      sss=8888
      
      # subp/s2.py
      res=99999
      
      # subp/s3.py
      from .s2 import res
    from ..subp.s1 import sss
    
    def fn():
        # 要使用s2中的res
    
        print('s3 fn run')
        print(res)
        
        #要使用s1中的sss
        print(sss)
        
      #mp/__init__.py
    from .subp.s3 import fn
      # t1.py
      mp.fn()
    
    # __name__ 代表路径
    文件结构:
    part3
    	->mp(m1.py, m2.py, m3.py,__init__.py)--> subp(s1.py,s1.py,s3.py __init__.py)
      ->t1.py
      
      # subp/s1.py
      sss=8888
      
      # subp/s2.py
      res=99999
      
      # subp/s3.py
      from .s2 import res
    from ..subp.s1 import sss
    
    def fn():
        # 要使用s2中的res
    
        print('s3 fn run')
        print(res)
        
        #要使用s1中的sss
        print(sss)
        
        # print(__name__)
        
      #mp/__init__.py
    from .subp.s3 import fn
      # t1.py
      mp.fn()
      
      # __name__ 最后的输出结果 mp.subp.s3
    

    包管理的好处

    包管理内部采用相对导入管理模块或者模块中的名字(变量/函数名),外部调用模块的文件采用绝对导入导入一个包名,实际上导入的是路径,这样做的好处是复用性高,外界想要使用包中的模块只要导入包的路径,接下来都不用修改内部代码
    
  • 相关阅读:
    最大熵模型
    python安装深度学习包theano,Pylearn2,scikit-neuralnetwork
    sklearn之learningcurve
    sklearn之validationcurve
    SVM
    一年7篇CVPR和4篇ICCV——女神
    CUDA大作业_进行图像特征匹配V2.0
    CUDA大作业_进行图像特征匹配V1.0
    从K近邻算法、距离度量谈到KD树、SIFT+BBF算法
    Ubuntu 开机出现 grub rescue> 终端模式修复方法
  • 原文地址:https://www.cnblogs.com/cjwnb/p/10823225.html
Copyright © 2020-2023  润新知