zoukankan      html  css  js  c++  java
  • 自定义模块

    自定义模块

    模块的定义与分类

    定义 : 模块,就是一些列常用功能的集合体。

    模块的作用(优点):

    • 程序的结构更清晰,方便管理,实现了功能的重复利用
    • 拿来主义,提升开发效率
    • 避免重复造轮子

    script (脚本)

    • 将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script,脚本就是一个python文件

    模块的分类

    第一类 : 内置模块 (标准库)

    • 由python解释器提供,例 time 模块 os 模块,标准库模块约(200多个,每个模块又有很多功能)

    第二类 : 第三方模块 (第三方库)

    • python大神写的非常好用的模块,必须通过 pip install 指令安装的模块,比如BeautfulSoup, Django,等等。大概有6000多个

    第三类 : 自定义模块

    • 自己在项目中定义的一些模块

    import 直接引用

    import 使用

    print('from the tbjx.py')   # 整体是 tbjx 模块
    name = '太白金星'
    
    def read1():
        print('tbjx模块:',name)
    
    def read2():
        print('tbjx模块')
        read1()
    
    def change():
        global name
        name = 'barry'
    

    模块包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块import很多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句),如下 import tbjx #只在第一次导入时才执行tbjx.py内代码,此处的显式效果是只打印一次'from the tbjx.py',当然其他的顶级代码也都被执行了,只不过没有显示效果.

    第一次导入模块执行三件事

    • 将模块文件加载到内存.(在执行文件中执行一次此模块)
    • 在内存中创建 一个 以 导入模块 命名的名称空间.
    • 通过 导入模块 名称空间的 模块 名字 + . 等方式引用此模块的名字(变量,函数名,类名等等).
    • ps:重复导入会直接引用内存中已经加载好的结果

    被导入模块有独立的名称空间

    • 每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突。
    • 坑 : 通过 导入模块 名称空间的 模块 名字 + . 的方式引用 此模块的名字时,一定一定是从 此模块 中寻找.
    • 通过 import 引用模块 他有自己的 独立名称空间 , 与当前 执行文件 没有关系.

    为模块起别名

    • 别名其实就是一个外号
    import tbjx as t
    t.read1()
    

    别名 应用 :

    • 好处可以将很长的模块名改成很短,方便使用
    • 有利于代码的扩展和优化 , 便于统一维护

    导入多个模块

    开发过程中,免不了会在一个文件中,导入多个模块,推荐写法是一个一个导入 , 即分开多行导入

    多行导入优点:

    • 易于阅读 / 易于编辑 / 易于搜索 / 易于维护
    import os,sys,json   # 这样写可以但是不推荐
    
    # 推荐写法
    
    import os
    import sys
    import json
    

    导入模块顺序

    内置模块 → 第三方模块 → 自定义模块

    • 模块的导入遵循PEP8规范:所有的模块导入都应该尽量放在这个文件的 开头

    from ... import ...

    from ... import ... 使用

    # from ..(模块名). import . (模块里的内容).. 的使用示例。
    from tbjx import name, read1  #相当于从tbjx模块的全局空间中将name,read1变量与值的对应关系复制到当前执行文件的全局名称空间中.
    print(name)
    read1()
    '''
    执行结果:
    from the tbjx.py
    太白金星
    tbjx模块: 太白金星
    '''
    

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

    唯一的区别就是

    • 使用from...import...则是将 导入模块 中的 变量名字 直接导入到 当前的 名称空间 中,所以在当前名称空间中,直接使用名字就可以了、无需加前缀:模块名 .
    • 好处:使用起来方便了
    • 坏处:容易与当前执行文件中的名字冲突 / 如果当前空间有变量名与导入模块的变量相同 , 后者将把前者覆盖 即↓
    • 执行文件有与模块同名的变量或者函数名,会有 覆盖效果 由下往上覆盖 ↑

    当前位置直接使用read1和read2就好了,执行时,仍然以tbjx.py文件全局名称空间

    一行导入多个 / 起别名

    from tbjx import read1,read2,name
    

    from ... import * (别单独用) 与 __all__ 结合使用

    __all__

    • 将模块中所有的变量名字复制过来,
    • 容易覆盖
    • __all__ 结合使用 __all__ 写在 模块文件
    __all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字
    

    py文件的两种功能

    编写好的一个python文件可以有两种用途:

    脚本( 承载文件 ) / 执行文件

    __name__ (在模块中调试数据)

    • 一个文件就是整个程序,用来被执行
    • 直接打印 __name__ 返回值为 ' __main__ '

    模块 / 被执行文件

    • 文件中存放着一堆功能,用来被导入使用
    • 直接打印 __name__ 返回值为 模块名

    python为我们内置了全局变量 __name__ :

    • 当文件当做脚本执行时: __name__ 等于' __main__ '
    • 当文件当做模块被执行时: __name__ 等于模块名

    作用:

    • 用来控制.py文件在不同的应用场景下执行不同的逻辑(或者是在模块文件中测试代码

    模块循环导入问题

    #创建一个m1.py
    print('正在导入m1')
    from m2 import y
    
    x='m1'
    
    #创建一个m2.py
    print('正在导入m2')
    from m1 import x
    
    y='m2'
    
    #创建一个run.py
    import m1
    
    #测试一
    执行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'
    
    
    #测试一结果分析
    先执行run.py--->执行import m1,开始导入m1并运行其内部代码--->打印内容"正在导入m1"
    --->执行from m2 import y 开始导入m2并运行其内部代码--->打印内容“正在导入m2”--->执行from m1 import x,由于m1已经被导入过了,所以不会重新导入,所以直接去m1中拿x,然而x此时并没有存在于m1中,所以报错
    
    
    #测试二:执行文件不等于导入文件,比如执行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'
    
    
    #测试二分析
    执行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
    
    方法二:导入语句放到函数中
    #m1.py
    print('正在导入m1')
    
    def f1():
        from m2 import y
        print(x,y)
    
    x = 'm1'
    
    # f1()
    
    #m2.py
    print('正在导入m2')
    
    def f2():
        from m1 import x
        print(x,y)
    
    y = 'm2'
    
    #run.py
    import m1
    
    m1.f1()
    

    模块的搜索路径

    内存中已经加载的模块 > 内置模块 > sys.path路径中包含的模块

    import sys
    # print(sys.path)
    sys.path.append(r'D:s15')
    # import tbjx
    import tbjx1
    tbjx1.read1()
    

    需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错

  • 相关阅读:
    济南学习 Day5 T3 晚
    Codevs 1043 ==洛谷 P1004 方格取数
    济南学习 Day 5 T2 晚
    济南学习 Day 5 T1 晚
    济南学习 Day 5 T3 am
    济南学习 Day 5 T2 am
    LeetCode Weekly Contest 8
    poj-1410 Intersection
    leetcode-Warm Up Contest-Aug.21
    poj-1384 Piggy-Bank
  • 原文地址:https://www.cnblogs.com/fanxss/p/11051640.html
Copyright © 2011-2022 走看看