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)
    
    
  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/xt12321/p/10672675.html
Copyright © 2011-2022 走看看