模块介绍

什么是模块

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

为什么要用模块

极大地提升开发效率

模块的三种来源

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

模块的使用

import语句

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

fuc.index()
# from function fuc

特点:

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

注意:

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

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名字

特点:

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

注意:

  1. 重复导入也只会导入一次
  2. 使用模块名称空间中的名字不需要加模块名前缀 直接使用即可
  3. from...import的句式会产生“名字”冲突的问题
  4. 使用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

注意

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

模块查找顺序

顺序

  1. 先从内存空间中查找
  2. 再从内置模块中查找
  3. 最后去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__':
    # 当前文件是执行文件的时候才会执行的子代码块
Last modification:March 25, 2022
如果觉得我的文章对你有用,请随意赞赏