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

    本节内容:

    一、模块及使用

    • 1.模块及使用
    • 2.起别名、from导入
    • 3.自执行与模块

    二、包的使用

    • 2.1 包中模块的使用:import
    • 2.2 包的嵌套
    • 2.3 包中模块的使用:from ...import
    • 2.4 导包的两种方式
    • 2.5 关于__init__

    一、模块及使用

    1.模块
    一系列功能的集合体
    
    2.定义模块
    创建一个py文件就是一个模块,该py文件名就是模块名
    
    3.为什么要使用模块
    1.从文件级别组织代码,使同特性的功能统一管理
    2.可以使用系统或第三方模块(拿来主义),来提高开发效率
    
    4.模块存在方式
    1.使用C语言编写并链接到Python解释器的内置模块
    2.已被编译为共享库或DLL的C或C++扩展
    3.使用Python编写的.py文件(任何一个py文件都可以作为模板)
    4.包:一堆py文件的集合体
    
    5.如何使用模块
    # 在要使用的该模块功能的文件中导入模块,通过import关键字导入模块名
    import module
    
    导入模块,会编译执行一个pyc文件,该pyc文件就是该模块的执行文件
    
    再次导入,module模块不会被执行了
    
    # 在任何地方都可以导入模块
    
    def fn():
        global m3
        import m3  # 就是普通的名字,只是该名字执行的是一个py文件
        print('>>>',m3.num)
        
    fn()
    print(m3.num)
    

    二、起别名、from导入

    1.起别名
    # 通过关键字as可以给模块起别名:模块一旦起别名,原模块名就不能再使用
    # 1.可以简化模块名字
    import mmmmmmmmmmmmm3 as my_m3
    print(my_m3.num)
    
    # 2.可以统一功能
    cmd = input('数据库选择  1.mysql  2.oracle :')
    if cmd =='1':
        import mysql as db
    #     mysql.excuse()
    else:
        import oracle as db
    #     oracle.excuse()
    
    db.excuse()
    
    # ------------------------
    mysql.py
    
    def excuse():
        print('this is mysql')
    # ------------------------
    oracle.py
    def excuse():
        print('this is oracle')
    
    2.from导入
    # 在import后的名字才会在该文件的名称空间中产生
    from m4 import a,b,_c  # 指名道姓的可以导入_开头的名字
    
    # 通过*导入: 可以将导入模块中的(除了以_开头的)名字一并导入
    
    from m4 import *  # 通常不建议导入* ,但需要使用模块中绝大部分名字时,才考虑导入*
    print(a)
    a()
    
    # 两个py文件中的名字a都合理存在
    # 但import后的名字a和a=20,在一个名称空间中,只会保留最后一次值
    a = 20
    b()
    # print(a)
    # print(_c)
    
    # ------------------------
    m4.py
    
    def a():
        print('a func')
    def b():
        a()
        print('b func')
    def _c():
        print('c func')
    
    # _c = 30
    # import _c as c
    
    # 需求:内部已经有_开头的名字,还想被外界通过 * 导入
    # 本质:导入 * 其实就是导入__all__列表中存放的索引名字,系统默认不会收录_开头的名字
    __all__ =['a', 'b', '_c']  # 通过自定义__all__来规定外界通过*可以导入的名字
    
    

    三、自执行与模块

    # __name__:
    # 1.在py文件作为模块被使用时,__name__为模块名
    # 2.在py文件自执行时,__name__为字符串 '__main__'
    # print(__name__)
    
    # ------------------------
    m6.py
    
    print("共有逻辑")
    if __name__ == '__main__':
        # 所有自执行的逻辑
        print("m6: 我是自执行的")
        a = 10  # 产生的是全局的名字
    else:
        # 所有模块的逻辑
        print("m6: 我被导入执行的")
        # print(a)  # 走else就不可能走if,所以a压根没产生
    
    

    --------------------2019.04.09------------------------

    1.1 模块的搜索路径

    搜索顺序:内存 -> 内置模块 -> sys.path
    
    1.导入模块会优先在内存中查找
    2.内存中没有被加载的话,再去查找内置模块
    3.还没有查找到,就根据sys.path中的路径顺序逐一查找
    

    1.2 模块导入的执行流程

    导入模块的指令:
    
    --相对于  函数名()调用函数体,函数调用会进入函数体,从上至下逐句解释执行函数体代码
    
    --导入模块,会进入模块文件,从上至下逐句解释执行模块文件代码
    
    --如果在模块中又遇到导入其他模块,会接着进入导入的模块,从上至下逐句解释执行文件中的代码,依次类推
    
    # 导入模块执行顺序
    # -----test.py---------
    import m3
    print(m3.a)
    print('end')
    
    # -----m3.py----------
    # import mm3
    from mm3 import x, y
    print('m3 imported')
    a = 10
    b = 20
    
    # -----mm3.py---------
    print('mm3 imported')
    x = 10
    y = 20
    
    # 程序执行过程可以理解为:
    # 执行test.py文件,先导入m3
    # 解释器导入m3.py文件,编译m3.py文件的时候,又导入了mm3.py文件
    # 解释器导入mm3.py文件,编译执行mm3.py文件,执行完返回m3.py文件中
    # 继续执行下面的内容,编译执行完m3.py文件之后,返回test.py文件
    # 继续执行导入操作下面的内容
    

    1.3 循环导入

    模块之间出现了环状导入,如:m1.py中导入了m2.py中又导入了m1
    
    循环导入的问题:
    --导入模块是要使用模块中的变量
    --正常逻辑都是在文件最上方先完成对模块的导入,再在下方定义自身模块变量,以及使用导入的模块中的变量
    --就会出现下面的情况,m2在使用m1中的变量x,但变量x却并未产生,这就出现了循环导入问题
    
    # ----m1.py文件--------
    import m2
    x = 10
    print(m2.y)
    
    # ----m2.py文件--------
    import m1
    y = 18
    print(m1.x)
    
    # 无论从执行m2.py文件还是m1.py文件(假设是m1.py文件),
    # 编译执行时都会导入另一个文件(m2.py文件),然后转至另一个文件(m1.py文件)
    # 发现又会导入原先的文件,此时,内存中已有原文件
    # 会直接编译执行(m2.py文件),结果就会报错
    # 原因是m1.py文件中的x值并没有读入内存。
    
    解决循环导入的问题:延后导入
        1.将循环导入对应包要使用的变量提前定义。再导入相应的包
        2.将导包的路径放到函数体中,保证存放导包逻辑的函数调用在要使用的变量定义之后
    
    重点:
        问题:from导包极容易出现循环导入问题
        解决:建议from导入方式改用import导入方式
    

    二、包的使用

    一系列功能模块的集合体
        --包就是管理功能相近的一系列模块的文件夹
        --该文件包含一个特殊文件__init__.py
        --文件夹名就是包名,产生的包名就是指向__init__.py的全局名称空间
    
    导包完成的三项事:
        1.编译执行包中的__init__.py文件,会在包中__pycache__创建对应的pyc文件
        2.产生__init__.py文件的全局名称空间,用来存放__inti__出现的名字
        3.产生包名指向__init__.py文件的全局名称空间 | 指向变量名指向包中指定名字
    

    2.1 包中模块的使用:import

    module文件夹
        --__init__.py
        --m1.py
        
    # ----test.py文件-------
    import module
    # 在该文件中使用包
    
    # 1. __init__.py文件中产生的普通名字可以直接使用
    __init__.py
    x = 10
    
    # ----test.py-----------
    print(module.x)
    
    # 2.管理的模块中出现的名字,要通过 包名.模块名 间接使用
    # ----m1.py-------------
    num = 10
    
    __init__.py
    import module.m1
    
    # ---test.py------------
    print(module.m1.num)
    

    2.2 包的嵌套

    # 在包中再定义包
    # 连包的导入
    
    import 父包.子包
    重点:导包的.语法,在所有点左侧都必须是包
    
    # 正确案例:
    import 父包.子包
    import 父包.子包.模块
    # 错误案例
    import 父包.子包.模块.名字
    

    2.3 包中模块的使用:from...import

    使用规则与import差不多,但是导包的.语法需严格执行,就是所有点左侧都必须是包
    

    2.4 导包的两种方式

    绝对导入:通过sys.path方式来实现
    相对导入:通过包内.语法来实现
    
    # 绝对导入
    
    将对应的文件夹添加至sys.path中,就可以直接导入对应文件夹下的模块
    
    # 相对导入
    
    相对导入是存在与包内的语法
    
    .代表当前文件夹
    ..代表上一级文件夹
    ...代表上一级的上一级文件夹
    
    存在.语法的文件,不能作为执行文件
    

    2.5 关于 init

    __init__.py 文件的作用是将文件夹变为一个Python模块,
    Python 中的每个模块的包中,都有__init__.py 文件。
    
    通常__init__.py 文件为空,但是我们还可以为它增加其他的功能。
    我们在导入一个包时,实际上是导入了它的__init__.py文件。
    这样我们可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入。
    

    今日(2019.04.08)补充内容:函数回调

    # 怎么样提前写出函数的调用:在另一个函数中写出函数的调用
    # 再去考虑函数体的实现:根据实际的需求
    
    def my_sleep(sec):
        import time
        current_time = time.time()
        while time.time() - current_time < sec:
            pass
    
    
    def download(fn=None):
        print('开始下载')
        my_sleep(1)
        data = '下载得到的信息'
        print('下载完成')
        if fn:  # 如果外界提供了回调函数的实现体,再去调用,否则就只完成默认下载的功能
            res = fn(data)  # 下载成功的回调函数,具体完成什么事之后决定
            if res:
                print('操作成功')
                return True
            print('操作失败')
            return False
        return data  # 没有外界具体操作下载结果的功能代码,就将下载结果直接返回
    
    # res = download()
    # print(res)
    
    def download_action(data):
        print('往文件中写')
        with open('1.txt', 'w', encoding='utf-8') as f:
            f.write(data)
            return True
        return False
    
    res = download(download_action)
    print(res)
    
    # 下载成功后的动作可以多样化
    def download_action1(data):
        print(data)
        return True
    res = download(download_action1)
    print(res)
    
    
  • 相关阅读:
    Redis 2种持久化模式的缺陷
    我看过得最易懂的一段AOP的解释
    mysql-高性能索引策略
    几款效率神器助你走上人生巅峰
    shell脚本报错:"[: =: unary operator expected"
    CentOS7中使用iptables
    php foreach用法和实例
    shell 学习四十五天---xargs
    chain issues incorrect order,EXtra certs,Contains anchor
    Ubuntu 能ping通DNS 地址 无法解析域名
  • 原文地址:https://www.cnblogs.com/xt12321/p/10672675.html
Copyright © 2011-2022 走看看