模块介绍
什么是模块
模块就是一系列功能的结合体 可以直接使用
为什么要用模块
极大地提升开发效率
模块的三种来源
- 内置的模块:无需下载 解释器自带 直接导入使用即可
- 自定义模块:自己写的代码 封装成模块 自己用或者发布到网上供别人使用
- 第三方模块:别人写的发布到网上的 可以下载使用的模块(很多好用的模块都是第三方)
模块的使用
import语句
# 文件名:func.py
def index():
print("from function index")
# 文件名:main.py
import fuc
fuc.index()
# from function fuc
特点:
- 相同的模块反复被导入只会执行一次
- 可以通过
import
后面的模块名点的方式 使用模块中所有的名字并且不会与当前名称空间中的名字冲突(指名道姓)
注意:
- 执行当前文件 产生一个当前文件的名称空间
- 执行
import
句式 导入模块文件(即执行模块文件代码产生模块文件的名称空间) - 在当前文件的名称空间中产生一个模块的名字 指向模块的名称空间
- 通过该名字就可以使用到模块名称空间中的所有数据
from-import 语句
# 文件名:func.py
def index():
print("from function index")
name = 'kevin'
# 文件名:main.py
from fuc import name
print(name)
# kevin
fuc.index() # 报错 from fuc import name 只使用模块中的name名字
特点:
- 执行当前文件产生一个名称空间
- 执行导入语句 运行模块文件产生名称空间存放运行过程中的所有名字
- 将import后面的名字直接拿到当前执行文件中
注意:
- 重复导入也只会导入一次
- 使用模块名称空间中的名字不需要加模块名前缀 直接使用即可
from...import
的句式会产生“名字”冲突的问题- 使用
from...import
的句式 只能使用import
后面出现的名字
其他导入语
给模块起别名(使用频率很高)
# 文件名:func.py
def index():
print("from function index")
name = 'kevin'
# 文件名:main.py
from fuc import name as n
print(n)
# kevin
连续导入多个模块或者变量名
# 文件名:func.py
def index():
print("from function index")
name = 'kevin'
# 文件名:main.py
from fuc import name, index
print(name)
# kevin
index()
# from fuc import name, index
print(name)
# kevin
index()
# from function index
通用导入
# 文件名:func.py
def index():
print("from function index")
name = 'kevin'
# 文件名:main.py
from fuc import * # *表示fuc里面所有的名字
print(name)
# kevin
index()
# from fuc import name, index
print(name)
# kevin
index()
# from function index
补充:模块的编写者可以在自己的文件中定义__all__
变量用来控制*
代表的意思。在另外一个文件中使用*
导入时,就只能导入__all__
定义的名字了
# 文件名:func.py
def index():
print("from function index")
name = 'kevin'
__all__ = [name]
循环导入问题
循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常,究其根源就是在python中,同一个模块只会在第一次导入时执行其内部代码,再次导入该模块时,即便是该模块尚未完全加载完毕也不会去重复执行内部代码
演示
# 文件名:index_1
import index_2
a = "from index_1"
# 文件名:index_2
import index_1
b = "from index_2"
print(index_1.a) # 调用index_1中变量名a,并运行
# 抛出异常
解决
方式1
将导入模块的句式写在定义名字的下面
# 文件名:index_1
a = "from index_1"
import index_2
# 文件名:index_2
import index_1
b = "from index_2"
print(index_1.a)
# from index_1
# from index_1
方式2
将导入模块的句式写在函数体代码内
# 文件名:index_1
def start():
import index_2
a = "from index_1"
return a
# 文件名:index_2
import index_1
b = "from index_2"
print(index_1.start())
# from index_1
# from index_1
注意
尽量去避免循环导入的问题,能不用则不用,当多个模块确实都需要共享某些数据,可以将共享的数据集中存放到某一个地方,然后进行导入
模块查找顺序
顺序
- 先从内存空间中查找
- 再从内置模块中查找
- 最后去
sy.path
查找(类似于环境变量)
验证
1.先从内存空间中查找
# 文件名:index_1
a = "from index_1"
# 文件名:index_2
import time
import index_1
time.sleep(10)
"""
再此期间将文件index_1,删除
"""
print(index_1.a)
# fom index_1
2.再从内置模块中查找
# 文件名:time
def time():
return "from time.py"
# 文件名:index_2
import time
print(time.time())
# 1648197154.0808792
"""
强调:在创建py文件时候一定不要跟模块名(内置、第三方)冲突!
"""
3.最后去sy.path
查找(类似于环境变量)
import sys
print(sys.path) # 结果是一个列表,当内存中和内置中都没有要查找的模块时,就会去下面的路径中挨个查找
# ['/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']
"""
只需重点关注第一个,第一个是执行文件的所在路径
"""
解决
解决如何在当前路径,引用目录中的文件模块
方式1
主动添加路径到sy.path
(类似于添加环境变量)
# 文件名:index_1 路径:'/Users/kevin/Desktop/python'
import sys
sys.path.append(r'/Users/kevin/Desktop/python/aaa/') # 绝对路径
# sys.path.append(r'aaa/') # 相对路径
import index_3
print(index_3.a)
# from index_3
"""
pycharm会自动将项目目录所在的路径添加到sys.path中
"""
# 文件名:index_3 路径:'/Users/kevin/Desktop/python/aaa'
a = "from index_3"
方式2
利用from...import...
句式“指名道姓”的查找
# 文件名:index_1 路径:'/Users/kevin/Desktop/python'
from aaa import index_3 # # 从文件夹aaa中导入index_3模块
print(index_3.a)
# from index_3
# 文件名:index_3 路径:'/Users/kevin/Desktop/python/aaa'
a = "from index_3"
# 通过点的方式进入下一层目录
from aaa.bbb.ccc import index_3
绝对导入与相当导入
绝对导入
永远按照执行文件所在的路径一层层往下查找
相对导入
相当导入打破了必须参照执行文件的所在路径的要求,只需要考虑当前模块所在的路径然后使用特殊符号.
去查找其他模块,并不能在执行文件中使用。不推荐使用
from . import 文件名(模块名)
"""
.表示当前路径
..表示上一层路径
../..表示上上一层路径
"""
判断文件类型
执行文件
当python
内置变量__name__
所在的文件是执行文件的时候,结果是__main__
# 文件名:index_1
print(__name__)
# __main__
被导入文件
当python
内置变量__name__
所在的文件是被导入文件时候,结果是文件名(模块名)
# 文件名:index_1
import index_2
# index_2
# 文件名:index_2
print(__name__)
补充
# 可以借助于__name__区分被导入的代码和测试代码
if __name__ == '__main__':
# 当前文件是执行文件的时候才会执行的子代码块