模块介绍

什么是模块

模块就是一系列功能的结合体 可以直接使用

为什么要用模块

极大地提升开发效率

模块的三种来源

  1. 内置的模块:无需下载 解释器自带 直接导入使用即可
  2. 自定义模块:自己写的代码 封装成模块 自己用或者发布到网上供别人使用
  3. 第三方模块:别人写的发布到网上的 可以下载使用的模块(很多好用的模块都是第三方)

模块的使用

import语句

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  1. # 文件名:main.py
  2. import fuc
  3. fuc.index()
  4. # from function fuc

特点:

  1. 相同的模块反复被导入只会执行一次
  2. 可以通过import后面的模块名点的方式 使用模块中所有的名字并且不会与当前名称空间中的名字冲突(指名道姓)

注意:

  1. 执行当前文件 产生一个当前文件的名称空间
  2. 执行import句式 导入模块文件(即执行模块文件代码产生模块文件的名称空间)
  3. 在当前文件的名称空间中产生一个模块的名字 指向模块的名称空间
  4. 通过该名字就可以使用到模块名称空间中的所有数据

from-import 语句

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  4. name = 'kevin'
  1. # 文件名:main.py
  2. from fuc import name
  3. print(name)
  4. # kevin
  5. fuc.index() # 报错 from fuc import name 只使用模块中的name名字

特点:

  1. 执行当前文件产生一个名称空间
  2. 执行导入语句 运行模块文件产生名称空间存放运行过程中的所有名字
  3. 将import后面的名字直接拿到当前执行文件中

注意:

  1. 重复导入也只会导入一次
  2. 使用模块名称空间中的名字不需要加模块名前缀 直接使用即可
  3. from...import的句式会产生“名字”冲突的问题
  4. 使用from...import的句式 只能使用import后面出现的名字

其他导入语

给模块起别名(使用频率很高)

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  4. name = 'kevin'
  1. # 文件名:main.py
  2. from fuc import name as n
  3. print(n)
  4. # kevin

连续导入多个模块或者变量名

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  4. name = 'kevin'
  1. # 文件名:main.py
  2. from fuc import name, index
  3. print(name)
  4. # kevin
  5. index()
  6. # from fuc import name, index
  7. print(name)
  8. # kevin
  9. index()
  10. # from function index

通用导入

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  4. name = 'kevin'
  1. # 文件名:main.py
  2. from fuc import * # *表示fuc里面所有的名字
  3. print(name)
  4. # kevin
  5. index()
  6. # from fuc import name, index
  7. print(name)
  8. # kevin
  9. index()
  10. # from function index

补充:模块的编写者可以在自己的文件中定义__all__变量用来控制*代表的意思。在另外一个文件中使用*导入时,就只能导入__all__定义的名字了

  1. # 文件名:func.py
  2. def index():
  3. print("from function index")
  4. name = 'kevin'
  5. __all__ = [name]

循环导入问题

循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常,究其根源就是在python中,同一个模块只会在第一次导入时执行其内部代码,再次导入该模块时,即便是该模块尚未完全加载完毕也不会去重复执行内部代码

演示

  1. # 文件名:index_1
  2. import index_2
  3. a = "from index_1"
  1. # 文件名:index_2
  2. import index_1
  3. b = "from index_2"
  4. print(index_1.a) # 调用index_1中变量名a,并运行
  5. # 抛出异常

解决

方式1

将导入模块的句式写在定义名字的下面

  1. # 文件名:index_1
  2. a = "from index_1"
  3. import index_2
  1. # 文件名:index_2
  2. import index_1
  3. b = "from index_2"
  4. print(index_1.a)
  5. # from index_1
  6. # from index_1

方式2

将导入模块的句式写在函数体代码内

  1. # 文件名:index_1
  2. def start():
  3. import index_2
  4. a = "from index_1"
  5. return a
  1. # 文件名:index_2
  2. import index_1
  3. b = "from index_2"
  4. print(index_1.start())
  5. # from index_1
  6. # from index_1

注意

尽量去避免循环导入的问题,能不用则不用,当多个模块确实都需要共享某些数据,可以将共享的数据集中存放到某一个地方,然后进行导入

模块查找顺序

顺序

  1. 先从内存空间中查找
  2. 再从内置模块中查找
  3. 最后去sy.path查找(类似于环境变量)

验证

1.先从内存空间中查找

  1. # 文件名:index_1
  2. a = "from index_1"
  1. # 文件名:index_2
  2. import time
  3. import index_1
  4. time.sleep(10)
  5. """
  6. 再此期间将文件index_1,删除
  7. """
  8. print(index_1.a)
  9. # fom index_1

2.再从内置模块中查找

  1. # 文件名:time
  2. def time():
  3. return "from time.py"
  1. # 文件名:index_2
  2. import time
  3. print(time.time())
  4. # 1648197154.0808792
  5. """
  6. 强调:在创建py文件时候一定不要跟模块名(内置、第三方)冲突!
  7. """

3.最后去sy.path查找(类似于环境变量)

  1. import sys
  2. print(sys.path) # 结果是一个列表,当内存中和内置中都没有要查找的模块时,就会去下面的路径中挨个查找
  3. # ['/Users/kevin/Desktop/python', '/Users/kevin/Desktop/python', '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_display', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_matplotlib_backend']
  4. """
  5. 只需重点关注第一个,第一个是执行文件的所在路径
  6. """

解决

解决如何在当前路径,引用目录中的文件模块

方式1

主动添加路径到sy.path(类似于添加环境变量)

  1. # 文件名:index_1 路径:'/Users/kevin/Desktop/python'
  2. import sys
  3. sys.path.append(r'/Users/kevin/Desktop/python/aaa/') # 绝对路径
  4. # sys.path.append(r'aaa/') # 相对路径
  5. import index_3
  6. print(index_3.a)
  7. # from index_3
  8. """
  9. pycharm会自动将项目目录所在的路径添加到sys.path中
  10. """
  1. # 文件名:index_3 路径:'/Users/kevin/Desktop/python/aaa'
  2. a = "from index_3"

方式2

利用from...import...句式“指名道姓”的查找

  1. # 文件名:index_1 路径:'/Users/kevin/Desktop/python'
  2. from aaa import index_3 # # 从文件夹aaa中导入index_3模块
  3. print(index_3.a)
  4. # from index_3
  1. # 文件名:index_3 路径:'/Users/kevin/Desktop/python/aaa'
  2. a = "from index_3"
  1. # 通过点的方式进入下一层目录
  2. from aaa.bbb.ccc import index_3

绝对导入与相当导入

绝对导入

永远按照执行文件所在的路径一层层往下查找

相对导入

相当导入打破了必须参照执行文件的所在路径的要求,只需要考虑当前模块所在的路径然后使用特殊符号.去查找其他模块,并不能在执行文件中使用。不推荐使用

  1. from . import 文件名(模块名)
  2. """
  3. .表示当前路径
  4. ..表示上一层路径
  5. ../..表示上上一层路径
  6. """

判断文件类型

执行文件

python内置变量__name__所在的文件是执行文件的时候,结果是__main__

  1. # 文件名:index_1
  2. print(__name__)
  3. # __main__

被导入文件

python内置变量__name__所在的文件是被导入文件时候,结果是文件名(模块名)

  1. # 文件名:index_1
  2. import index_2
  3. # index_2
  1. # 文件名:index_2
  2. print(__name__)

补充

  1. # 可以借助于__name__区分被导入的代码和测试代码
  2. if __name__ == '__main__':
  3. # 当前文件是执行文件的时候才会执行的子代码块