• 模块


    一 模块介绍

      1、什么是模块:

        模块就是一系列功能的集合体,分为三大类

          I:内置的模块
          II:第三方的模块
          III:自定义的模块

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

      2、为何要有模块:

        I:内置与第三的模块拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率

        II:自定义的模块

          可以将程序的各部分功能提取出来放到一模块中为大家共享使用,好处是减少了代码冗余,程序组织结构更加清晰

      3、如何用模块

        3.1import 模块名  如:import foo

        首次导入模块会做三件事:

          1、执行源文件代码

           2、产生一个新的名称空间用于存放源文件执行过程中产生的名字

           3、在当前执行文件所在的名称空间中得到一个名字foo,该名字指向2中产生的名称空间

           之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码

        1.引用

    print(foo.x)
    print(foo.get)
    print(foo.change)

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

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

        2.可以以逗号为分隔符在一行导入多个模块
          建议如下所示导入多个模块
          import time
          import foo
          import m
          不建议在一行同时导入多个模块
          import time,foo,m

        3.导入模块的规范

          I. python内置模块

          II. 第三方模块

          III. 程序员自定义模块

        4.模块中的as

          import ...as ...

          import foo as f 

          f.get()

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

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

          def func():

            import foo

        7.impot导入模块在使用时必须加前缀"模块."

        优点:肯定不会与当前名称空间中的名字冲突

        缺点:加前缀显得麻烦

        3.2 from-import 语句

        from...import...与import语句基本一致,唯一不同的是:使用from foo import x,get,change,Foo则可以在当前执行文件中直接引用模块foo中的名字,如下

    from foo import x,get,change #将模块foo中的x和get导入到当前名称空间
    a=x #直接使用模块foo中的x赋值给a
    get() #直接执行foo中的get函数
    change() #即便是当前有重名的x,修改的仍然是源文件中的x

        from ... import ...导入也发生了三件事

          1、产一个模块的名称空间

          2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去

          3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址

        from...impot...导入模块在使用时不用加前缀

          优点:代码更精简

          缺点:容易与当前名称空间混淆

        另外from语句支持from foo import 语法代表将foo中所有的名字都导入到当前位置:不推荐使用

    from foo import * #把foo中所有的名字都导入到当前执行文件的名称空间中,在当前位置直接可以使用这些名字
    
    a=x
    get()
    change()
    obj=Foo()

        模块的编写者可以在自己的文件中定义__all__变量用来控制*代表的意思

    #foo.py
    __all__=['x','get'] #该列表中所有的元素必须是字符串类型,每个元素对应foo.py中的一个名字
    x=1
    def get():
        print(x)
    def change():
        global x
        x=0
    class Foo:
        def func(self):
           print('from the func')

        这样我们在另外一个文件中使用*导入时,就只能导入__all__定义的名字了

    from foo import * #此时的*只代表x和get
    
    x #可用
    get() #可用
    change() #不可用
    Foo() #不可用

        关于import和from...import...的区别

        3.3 模块的搜索路径优先级

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

        优先级:1、内存(内置模块)2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块

    import sys
    print(sys.path)
    #值为一个列表,存放了一系列的对文件夹
    #其中第一个文件夹是当前执行文件所在的文件夹

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

    import sys
    import foo # foo=模块的内存地址
    def func():
        import foo # foo=模块的内存地址
    func()
    print('foo' in sys.modules)

        找foo.py就把foo.py的文件夹添加到环境变量中

    sys.path.append(r'路径')

         

        3.4循环导入问题

        循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常。循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常

    #m1.py
    print('正在导入m1')
    from m2 import y
    x='m1'
    
    #m2.py
    print('正在导入m2')
    from m1 import x
    y='m2'
    
    #run.py
    import m1

        测试一

    #1、执行run.py会抛出异常
    正在导入m1
    正在导入m2
    Traceback (most recent call last):
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/aa.py", line 1, in <module>
        import m1
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
        from m2 import y
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
        from m1 import x
    ImportError: cannot import name 'x'
    
    #2、分析
    先执行run.py--->执行import m1,开始导入m1并运行其内部代码--->打印内容"正在导入m1"
    --->执行from m2 import y 开始导入m2并运行其内部代码--->打印内容“正在导入m2”--->执行from m1 import x,由于m1已经被导入过了,所以不会重新导入,所以直接去m1中拿x,然而x此时并没有存在于m1中,所以报错

        测试二

    #1、执行文件不等于导入文件,比如执行m1.py不等于导入了m1
    直接执行m1.py抛出异常
    正在导入m1
    正在导入m2
    正在导入m1
    Traceback (most recent call last):
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
        from m2 import y
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
        from m1 import x
      File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
        from m2 import y
    ImportError: cannot import name 'y'
    
    #2、分析
    执行m1.py,打印“正在导入m1”,执行from m2 import y ,导入m2进而执行m2.py内部代码--->打印"正在导入m2",执行from m1 import x,此时m1是第一次被导入,执行m1.py并不等于导入了m1,于是开始导入m1并执行其内部代码--->打印"正在导入m1",执行from m1 import y,由于m1已经被导入过了,所以无需继续导入而直接问m2要y,然而y此时并没有存在于m2中所以报错

        解决方案

    # 方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
    # 文件: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()
    解决方案

        注意:循环导入问题大多数情况是因为程序设计失误导致,上述解决方案也只是在烂设计之上的无奈之举,在我们的程序中应该尽量避免出现循环/嵌套导入,如果多个模块确实都需要共享某些数据,可以将共享的数据集中存放到某一个地方,然后进行导入

  • 相关阅读:
    学习笔记:模拟退火
    我的 2020
    高一上文化课期末复习
    IOI 2020-2021 集训队作业
    学习笔记:插头DP
    NOIP2020 游记
    刷题记录
    学习笔记:四边形不等式优化 DP
    操作集合时 报错 java.lang.UnsupportedOperationException
    【编码】接收前端参数时,偶数汉字正常,奇数汉字乱码
  • 原文地址:https://www.cnblogs.com/bk134/p/12575839.html
Copyright © 2020-2023  润新知