zoukankan      html  css  js  c++  java
  • day21

    1. 模块

    1.1 什么是模块?
        # 模块是已经写好的一组功能的集合
        # 别人写好的函数 变量 方法 放在一个文件里 (这个文件可以被我们直接使用)这个文件就是一个模块
        # 模块可以是:py文件 dll文件 zip文件
    
    1.2 如何自己写一个模块
        # 创建一个py文件,给它起一个符合变量名命名规则的名字,这个名字就是模块名

     2. 模块的导入

    2.1 import 模块名
        假设有在同级目录下有一个my_module.py文件
        my_module.py:
        ------------------------------
            print(12345)
    
            name = 'alex'
    
            def read1():
                print('in read1 func')
    
            def read2():
                print("in read2 func", name)
    
            print(54321)
        ------------------------------
        # 在导入模块的过程中发生了什么?
            import my_module
            结果: 12345
                    54321
    
        总结:导入一个模块就是执行一个模块
    
        # 怎么使用my_module模块中的名字
        print(my_module.name)  # alex
        print(my_module.read1)  # <function read1 at 0x0000017D5B7E9510>
        my_module.read1()  # in read1 func
    
        # improt的命名空间,模块和当前文件在不同的命名空间中
        name = 'egon'
        def read1():
            print("main read1")
    
        print(name)  # egon
        print(my_module.name)  # alex
    
        # 模块只能用自己命名空间的变量,不能用当前空间的,因为没有执行关系
        name = 'egon'
        def read1():
            print("main read1")
    
        print(name)  # egon
        print(my_module.name)  # alex
        my_module.read2()  # in read2 func alex
    
        总结:每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突
        ---------------------------------------
        # 模块是否可以被重复导入?
        import my_module
        import my_module
        结果: 13245
              54321
    
        总结:第一次导入后就将模块名加载到内存,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句。
    
        # 怎么判断这个模块已经被导入过了???
        import sys
        print(sys.modules)
    
        # 模块导入的过程中发生了什么?
        # 找到这个模块
        # 判断这个模块是否被导入过了
        # 如果没有导入过
            # 创建一个属于这个模块的命名空间
            # 让模块的名字 指向 这个空间
            # 执行这个模块中的代码
        ------------------------------------
        # 给模块起别名,起了别名之后,使用这个模块就都使用别名引用变量了
        import my_module as m  # 12345 54321
        m.read1()  # in read1 func
    
        # json pickle
        # dumps loads
        def func(dic, t = 'json'):
            if t == 'json':
                import json
                return json.dumps(dic)
            elif t == 'pickle':
                import pickle
                return pickle.dumps(dic)
        # 直接用别名,简化代码
        def func(dic, t = 'json'):
            if t == 'json':
                import json as aaa
            elif t == 'pickle':
                import pickle as aaa
            return aaa.dumps(dic)
        -----------------------------------
        # 导入多个模块/分别起别名
            import os,time
            import os as o,time as t
    
        # 规范建议 模块应该一个一个的导入: 内置模块,第三方模块,自定义模块
    
        # 所以导入模块是有顺序的:
            # 内置模块
            # 扩展(第三方模块)
            # 自定义模块
    
        # 大家都符合这个规范,是为了大家用彼此模块很方便
        # import os
    
        # import django
    
        # import my_module
    2.2 模块的导入from import
        # 如何使用 from import?
            # 需要从一个文件中使用哪个名字,就把这个名字导入进来
            # from my_module import name
    
        # from import的过程中仍然会执行了这个被导入的文件
        -------------------------------------------------------------
        # import谁就只能用谁
        from my_module import read1  # 第一次导入,创建命名空间,执行这个文件,找到要导入的变量,创建引用指向要导入的变量.
        read1()  # in read1 func 这里只导入了read1,所以只能用read
    
        # 想要使用read2,还要再导入read2
        from my_module import read2  # 上面已经导入过,所以直接找到要导入的变量,创建引用指向要导入的变量.
        read2()  # in read2 func alex
        --------------------------------------------------------------------
        # 覆盖问题
        from my_module import read1  # 第一次被导入,创建命名空间,执行,找到变量,创建引用指向要导入的变量
        def read1():  # 这里重新定义了read1,所以导入进来的模块中的read1倍覆盖
            print("in my read1")
        read1()  # in my read1
    
        from my_module import read2  # 已经被导入过,直接找到变量,创建引用指向要导入的变量
        read2()  # in read2 func alex
        --------------------------------------------------------------
        # 一行导入多个名字?
        from my_module import read1, read2  # 12345 54321
        read1()  # in read1 func
        read2()  # in read2 func alex
        -------------------------------------------------------------------
        # 给导入的名字起别名
        from my_module import read1 as r1, read2 as r2
         read1():
            print("in my read1")
        r1()  # in read1 func
        r2()  # in read2 func alex
        read1()  # in my read1
        ------------------------------------------------------------------
        # from my_module import * 在导入的过程中 内存的引用变化
        from my_module import *  # 导入my_module.py文件中的所有成员
        name = 'egon'  # name被覆盖
        print(name)  # egon
        read1()
        read2()  # 用的是自己空间的alex
        ----------------------------------------------------------------
        # * 和 __all__  __all__能够约束*导入变量的内容
        修改:在my_module.py文件的上面加上一行__all__ = ['name']
        from my_module import *  # 12345 54321
        print(name)  # alex
        read1()  # 报错
        read2()  # 报错
    
        # __all__ 只能约束*

    3. 模块中引用的情况

    3.1 模块的循环引用 ☆☆☆
        # 模块之间不允许循环引用
        # 比如以下这些情况:
    
    
    
    
    
    

       模块a和模块b的引用构成了一个循环

    3.2 模块的加载与修改 ☆
        ------------------------------------------
        import time  # 导入时间模块
        import my_module  # 导入my_module.py文件,此时read1函数里是打印111
        
        time.sleep(10)  # 程序在这里停止10s,假设我在这里修改了打印为222
        my_module.read1()  # 那么这里打印的还是111,因为导入的时候已经存在于内存当中了,你修改的是文件里面的,你修改不了内存
    
        总结: 已经被导入的模块发生了修改,是不会被感知到的
        ----------------------------------------------------
        import time  # 导入时间模块
        import importlib
        import my_module  # 导入my_module.py文件,此时read1函数里是打印111
    
        time.sleep(10)  # # 程序在这里停止10s,假设我在这里修改read1函数打印的为222
        importlib.reload(my_module)  # 重新导入模块my_module,此时内容已经被修改
        my_module.read1()  # 所以此时read1打印的是222
    
        总结: 要想修改的模块被正在运行中的程序感知到,重启这个程序(或者重新加载模块)
    3.3 把模块当初脚本执行 ☆☆☆☆☆
        # 执行一个py文件的方式:
            # 在cmd里执行/在pycharm执行: 直接执行这个文件 - 以脚本的形式运行这个文件
            # 导入这个文件
        
        # 都是py文件
            # 直接运行这个文件 这个文件就是一个脚本
            # 导入这个文件   这个文件就是一个模块
    
        有calculate.py文件,里面是一个计算器
        -----------------------------------------------
        def main(exp):
            exp = exp.replace(' ', '')
            while 1:
                ret = re.search('([^()]+)', exp)
                if ret:
                    inner_backet = ret.group()
                    res = str(cal(inner_backet))
                    exp = exp.replace(inner_backet, res)
                    exp = format_exp(exp)
                else:
                    break
            return cal(exp)
    
        s = input(">>>")
        print(main(s))
        -------------------------------------------------
        假设我直接执行这个文件,此时它是脚本,它可以独立的提供一个功能
        但是假设我从同级目录的文件导入它,此时它是一个模块,能够被导入者调用这个功能,会先执行交互,但是我们不需要这个交互
        
        # 当一个py文件
        # 当做一个脚本的时候: 能够独立的提供一个功能,能自主完成交互
        # 当成一个模块的时候: 能够被导入者调用这个功能,不能自主交互
    
    # 一个文件中的__name__变量
        # 当这个文件被当做脚本执行的时候 __name__ == '__main__'
        # 当这个文件被当前模块导入的时候 __name__ == '模块的名字'
    
        这时我们可以用__name__ 来完成脚本和模块的需求
        将    if __name__ == '__main__':
                   s = input(">>>")
                   print(main(s))    放在calculate.py文件的最下面,
        当我们直接执行这个文件时,如果__name__等于'__main__',就可以执行交互,else:当它被当做模块导入时,__name__等于'模块的名字'
        此时calculate.py文件为
        ------------------------------------------
            def main(exp):
            exp = exp.replace(' ', '')
            while 1:
                ret = re.search('([^()]+)', exp)
                if ret:
                    inner_backet = ret.group()
                    res = str(cal(inner_backet))
                    exp = exp.replace(inner_backet, res)
                    exp = format_exp(exp)
                else:
                    break
            return cal(exp)
        if __name__ == '__main__'
            s = input(">>>")
            print(main(s))
    3.4 模块搜索路径 ☆☆☆☆☆
        # 和被当做脚本执行的文件 同目录下的文件 可以直接被导入
            因为被当做脚本直接执行这个文件,模块搜索路径中有这个文件的所在的目录,所有这个文件同级的模块可以被直接导入,因为他们的目录都一样
    
        # 除此之外其他路径下的模块 在被导入的时候需要自己修改sys.path列表

     4. 包

    4.1 什么是包?
        # 包: 文件夹中有一个__init__.py文件
        # 包: 是几个模块的集合
    
    4.2 包的导入语句
        
        # import  从包当中导入模块
        # import glance2.api.policy
        # glance2.api.policy.get()
        
        # import glance2.api.policy as policy
        # policy.get()
        
        # from import  导入模块,或者导入模块中的方法
        # from glance2.api import policy
        # policy.get()
        
        # from glance2.api.policy import get
        # get()
    
        # 关于包相关的导入语句也分为import和from ... import ...两种,但    是无论哪种,无论在什么位置,
        # 在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。
    
        # 需要注意的是from后import导入的模块,必须是明确的一个不能带点,
        # 否则会有语法错误,如:from a import b.c是错误语法
    4.3 绝对导入/相对导入
        (1)直接导入包
            # 导入一个包
                # 不意味着这个包下面的所有的内容都是可以被使用的
                # 导入一个包到底发生了什么?
                # 相当于执行了这个包下面的__init__.py文件
    
        (2)绝对导入
            # 绝对导入:
            # 优点:
                # 在执行一个python脚本的时候,这个脚本以及和这个脚本同级的模块只能用绝对导入
            # 缺点:
                # 所有的导入都要从一个根目录下往后解释文件夹之间的关系
                # 是是如果当前导入包的文件和被导入的包的位置发生了变化,那么所有init文件都要做相应的调整
    
        (3)相对导入
            # 相对导入
            # 优点:
                # 不需要去反复的修改路径
                    # 只要一个包中的所有文件夹和文件的相对位置不发生改变
                # 也不需要去关心当前这个包和被执行文件之间的层级关系
            # 缺点:
                # 含有相对导入的py文件不能被直接执行
                # 必须放在包中被导入的调用才能正常执行
    
        # 如果只是从包中导入模块的话,那么我们不需要做任何多余的操作
        # 直接导入就行了
    
        # 如果我们希望导入包的时候,能够顺便把模块也导进来
        # 需要设计init文件
        # 绝对目录的导入相对目录的导入各有千秋
  • 相关阅读:
    团队项目-第一阶段冲刺7
    团队项目-第一阶段冲刺6
    Spring Boot 揭秘与实战(七) 实用技术篇
    Spring Boot 揭秘与实战(七) 实用技术篇
    Spring Boot 揭秘与实战(六) 消息队列篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(四) 配置文件篇
  • 原文地址:https://www.cnblogs.com/kangqi452/p/11509070.html
Copyright © 2011-2022 走看看