zoukankan      html  css  js  c++  java
  • 模块与包

    什么是模块

    模块就是一系列功能的几何体,分为三大类:

    Ⅰ:内置的模块
    print(type(print))
    
    Ⅱ:第三方的模块
    import time
    print(type(time))
    
    Ⅲ:自定义的模块
    一个Python文件 本身就是一个模块,文件名:m.py,模块名:m

    模块分为4种形式

    • 1.使用Python编写的.py文件
    • 2.已被编译为共享库 或 DLL的 C 或者 C++扩展
    • 3.把一系列模块组织到一起的文件夹(注:文件夹下面有一个__init__.py文件,该文件夹称之为“包”)
    • 4.使用C编写 并链接到Python解释器的内置模块

    为何要用模块

    • 1.内置与第三方库模块 拿来就用,无序定义,这种拿来主义,可以极大地提升自己的开发效率
    • 2.自定义模块

    可以将程序的各个部分功能提取出来 放到一个模块中 供大家使用

    好处是 减少了代码冗余,程序组织结构更加清晰

    如何用模块

    1.首次导入模块会发生3件事

    ① 执行foo.py

    ② 产生foo.py的名称空间,将foo.py运行过程中产生的名字都丢到foo的名称空间中

    ③ 在当前文件中 产生一个名字foo,该名字 指向2中产生的名称空间

    y = 333
    x = 444
    import foo

    2.引用

    强调1:模块名.名字 是指名道姓地 问某一个模块 要对应的值,不会与当前名称空间中的名字发生冲突

    import foo
    
    print(foo.x)
    print(foo.get)
    print(foo.change)
    x = 11111
    print(x)
    print(foo.x)

    强调2:无论是查看 还是 修改,操作的都是模块本身,与调用位置无关

    import foo
    x = 33333
    # foo.get()
    
    foo.change()
    print(x)
    print(foo.x)

    3.可以以 , 为分隔符,在一行导入多个模块,但是不建议写在一行

    建议方式:
    import time
    import foo
    import fun1
    
    
    不建议方式:
    import time,foo,fun1

    4.导入模块的规范

    Ⅰ Python内置模块
    import time
    import sys
    
    Ⅱ 第三方模块
    import 第三方1
    import 第三方2
    
    Ⅲ 程序员自定义模块
    import 自定义模块1
    import 自定义模块2
    import 自定义模块3

    5.import ... as ...

    # import foo as f # f=foo 起别名
    # f.get()
    # import abcdefgadfadfas as mmm
    #
    # mmm.f1
    # mmm.f2
    # mmm.f3

    6.模块是第一类对象

    import foo

    7.自定义模块的命名应该采用纯小写+下划线的风格

    8.可以在函数内导入模块

    def func():
        import foo

    什么是包

    包就是一个含有___init__.py的文件夹
    在导包的时候,导入的其实__init__.py文件
    包的本质其实模块的一种形式
    

    为何要有包

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

    1.产生一个名称空间

    2.运行包下的__init__.py文件,将运行过程中产生的名字都丢到1的名称空间中

    3.在当前执行文件的名称空间

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

    包的使用

    1.导入包与___init___.py

    1.首次导入会运行包内__init__文件内的代码
    2.产生__init__文件的名称空间,将运行__init__文件时产生的名字都求导该名称空间中
    3.在执行文件中得到一个全局名称----包的名字(bag),该名字指向__init__.py文件的名称空间
    
    import new
    print(new.x)  # 会去找new包下的__init__.py,相当于print(__init__.x)
    from new import x
    print(x)
    

    2.一个python文件有两种用途

    ① 被当成程序运行

    为了区别同一个文件的不同用途,每个py文件都内置了__name__变量,该变量在py文件被当做脚本执行时赋值为“__main__”,在py文件被当做模块导入时赋值为模块名
    

    ② 被当做模块导入

    作为模块foo.py的开发者,可以在文件末尾基于__name__在不同应用场景下值的不同来控制文件执行不同的逻辑
    

    3.二者的区是什么?

    ① 作为程序运行

      直接右键运行该Python文件

    ② 作为模块导入

      作为模块,被import导入到其他文件中

    导入模块/包的2种方式

    方式一:import + 模块名

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

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

    # impot导入模块在使用时必须加前缀"模块."
    
    1、产一个模块的名称空间
    2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
    3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址
    from foo import x # x=模块foo中值0的内存地址
    from foo import get
    from foo import change

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

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

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

    # from foo import x   # x = 模块foo中 值1 的内存地址
    # x = 1111
    
    # 一行导入多个名字(不推荐使用)
    # from foo import x,get,change
    
    # *:导入模块中的所有名字(不推荐使用)
    # from foo import *
    # print(x)
    # print(get)
    # print(change)
    
    # 了解:__all__
    # from foo import *
    # print(x)
    # print(get)
    # print(change)
    # __all__ = [] 可以控制*
    
    # 起别名
    # from foo import get as g
    # print(g)

    绝对导入与相对导入

    绝对导入,以包的文件夹作为起始来进行导入

    from bag.this import x    # 导入在bag包下this.py文件夹中的变量x
    
    print(x)

    相对导入:仅限于包内使用,不能跨出包(包内模块之间的的导入,推荐使用相对导入)

    # .:表示当前文件夹
    # ..:表示上一层文件夹
    # 局限性:.不能超出foo之外
    # 注意:相对导入仅限于包内使用,不能跨出包,否则会出现语法错误
    # 包内的相互导入推荐使用相对导入
    
    from .this import # 导入在当前包内的this.py文件夹中的变量x
    
    print(x)

    两种导入方式对比

    两种导入模式的优缺点:
    
    绝对导入:(类似于绝对路径)
    以顶级的包为起始,点的形式往下找子包,一定能找到
    更改包名或着模块名的时候,导入的方式全部要改变
    能够导入任意地方的包
    
    相对导入:(类似于相对路径)
    包内模块彼此之间的导入,推荐使用相对导入
    当对包名更改时,因为只考虑在包内的相对位置
    不能跨出包

    模块的搜索路径优先级

    无论是import还是from...import在导入模块时都涉及到查找问题

    # 优先级:
    # 1、内存(内置模块)
    # 2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块
    # import sys
    # 值为一个列表,存放了一系列的对文件夹
    # 其中第一个文件夹是当前执行文件所在的文件夹
    # print(sys.path)
    # import foo # 内存中已经有foo了
    # foo.say()
    #
    # import time
    # time.sleep(10)
    #
    # import foo
    # foo.say()

    了解:sys.modules查看已经加载到内存中的模块

    import sys
    import foo  # foo = 模块的内存地址
    del foo
    
    print(sys.modules)

    循环导入

    循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块
    而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常
    m1.py
    print('正在导入m1')
    from m2 import y
    
    x='m1'
    m2.py
    print('正在导入m2')
    from m1 import x
    
    y='m2'
    run.py
    import m1
    
    输出:
    正在导入m1
    正在导入m2
    
    ImportError: cannot import name 'x' from partially initialized module 'm1' (most likely due to a circular import) (E:Python学习相关Teacherm1.py)
    
    解决方法:
    方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
    方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码

    思维导图(点击链接

  • 相关阅读:
    Spring Cloud是什么
    IDEA中常用的10款插件
    Spring Boot自动配置原理分析
    Spring Security自定义授权管理
    Docker常用命令
    pycharm设置开启时不直接打开最后关闭的项目
    django.db.migrations.exceptions.NodeNotFoundError: Migration users.0001_initial dependencies reference nonexistent parent node ('auth', '0009_auto_20200720_0228')
    使用anaconda创建虚拟环境
    windows安装rabbitmq
    docker安装并配置RabbitMQ
  • 原文地址:https://www.cnblogs.com/zhww/p/12983984.html
Copyright © 2011-2022 走看看