模块是什么:  *****
        模块 是一系列功能的集合体
        一个py文件就是一个模块
        一个函数就是一个功能
        例如 A.py   文件名A.py 模块名 A
模块有哪些来源
   内置
   第三方
   自定义
模块有四种通用的类别:
        1.自定义模块 *****
            (第三方模块也属于自定义 它是别的程序员写的 )
            关注如何自定义
        2.内置模块 ****
            是c语言写的 然后连接到python解释器中
            例如 time模块
            关注如何使用
        3.已经编译为DLL c或c++ ***
            不需要知道怎么来的 会用就行
        4.包  *****
           包实际上是包含一堆模块的文件夹
           之后详细将
        对于这四种模块 它们的使用方式 是一致的
如何定义模块:*****
    创建一个py文件  把你的功能写到文件中
为何用模块:
    1,使用内置和第三方的模块:拿来主义可以极大地提高开发效率
    2,使用自定义模块:为了减少代码冗余
如何使用模块:*****
    大前提:使用模块必须区分开谁是执行文件,谁是被导入的模块
    import 模块名
        使用:必须加前缀(模块名.)
        优点:指名道姓地向某一个模块的名称空间要名字,肯定不会与当前执行文件名称空间中的名字冲突
        缺点:必须加前缀,不够简洁
        首次导入模块发生3件事(import spam):
                1. 产生一个模块的名称空间
                2. 执行被导入spam.py内的代码,将执行过程中产生的名字丢存放于模块的名称空间中
                3. 在当前执行文件中拿到一个模块名,该名字是指向模块的名称空间的
    from 模块名 import名字
        使用:直接使用名字
        优点:无需加前缀,使用更为简洁
        缺点:容易与当前执行文件名称空间中的名字冲突
        首次导入模块发生3件事(from spam import money):
                1. 产生一个模块的名称空间
                2. 执行spam.py内的代码,将执行过程中产生的名字丢存放于模块的名称空间中
                3. 在当前执行文件中拿到一个名字money,该名字直接指向模块的名称空间的那个money的内存地址
    注意: 函数的作用域关系在定义阶段就已经固定死了,与调用位置无关
简单的说其实就是得到了一个名称 这个名字指向被导入文件
一旦有了这个名称我们就可以通过这个名称找到对应的命名空间中的所有名称
import 的其他写法 *****
    1.import xxx  as xxx
    给模块取别名 用于简化书写
    6 from xxx import xx as xx
    取别名
    2.import xxx,xxxx
    一次导入多个模块
    4.from xxx import xxx,xxx,xx
    从模块中导入多个名称
    3.from xxx import xxx
        从模块中导入某个名字到当前名称空间
        注意 要避免名称冲突
        如果冲突了 按照就近查找原则
    5.from xxx import *
        从模块中导入所有名称
        __all__用于控制 使用者可以使用哪些名称
    from 和 import 除了导入的名称 不同 其他特性一致
思考:
在模块的使用.py文件中
加入:
import spam
import spam
import spam
import spam
问:"from the spam" 输出几次?
答案是1次: 模块的中代码仅在首次导入时执行一次
执行文件和被导入的模块的命名空间 是相互独立的 ****
    在被导入模块中 所有的名字使用的都是自己空间中的  和调用者无关
py文件的两种执行方式 *****
    1.作为执行文件  (右键run)
    2.作为模块被导入
    __name__ 这个名称 可以获取当前执行状态
    如果是__main__ 说明当前是执行文件
    否则 说明是作为模块
    于是乎有了以下代码
        if __name__ == "__main__":
            print("作为执行文件")
        else:
            print("作为模块导入了")
模块的搜索路径的优先级
    内存中已经加载过的 -> 内置模块 -> sys.path #  第一个值是当前执行文件所在的文件夹
    sys.modules 查看内存中已加载的
    其中只有sys.path 我们可以操作
    通常我们会将模块的路径手动添加到sys.path中
# 方案一:
# import sys
# sys.path.append(r'D:\脱产三期视频\day16\03 模块的搜索路径1\dir1')
# print(sys.path)
# import m1
# m1.f1()
# 方案二:
# from dir1 import m1
# m1.f1()
from dir1.dir2 import m2
m2.f2()