模块
一、模块的简介
1. 什么是模块?
就是一系列功能的集合体
2.模块的本质
内部具有一定的功能(代码)的py文件
3. 为什么要用模块?
拿来主义,极大地提高了开发效率
4. 模块的来源
- 内置的: python解释器自带的,直接拿来使用的
- eg:import time - 第三方的 别人写的,如果想用,就要先下载在使用
- 自定义的 我们自己写的
5. 模块的存在形式
- 我们自己写的py文件(一个py文件就是一个模块)
- 包:一系列py文件的集合(文件夹)
- 一个包里面会有一个__init__.py文件
- 已被编译为共享库或DLL的c或C++扩展(了解)>>>第三方插件
- 使用C编写并链接到python解释器的内置模块(了解)
以后再写一个复杂项目的功能时候,要先考虑有没有被人已经写好的模块,我们直接拿来使用
二、模块的使用
2.1 import句式
"""
强调:
1.一定要搞清楚谁是执行文件 谁是被导入文件
2.以后开发项目的时候py文件的名称一般是纯英文
不会含有中文甚至空格
01 作业讲解.py 不会出现
test.py views.py 出现
"""
2.1.1 底层原理
在导入模块的时候,只有第一次会执行,其他的都不会执行
import md # 导入模块的时候,文件名后缀不能加
首次导入模块发生了什么事情?
- 运行执行文件,产生执行文件的全局名称空间
- 运行导入文件(md.py)
- 产生导入文件的全局名称空间,并且,把导入文件中产生的名字都保存到导入文件的全局名称空间
- 在执行文件中,产生一个md的名字(模块名)指向导入文件的全局名称空间
一旦你使用了import句式之后,我们就可以通过句点符的形式找到导入文件中得名字
2.1.2 使用
import md # 导入模块md.py
print(md.money)
md.read1()
md.read2()
md.change()
money = 666
print(md.money) # 1000
print(money) # 666
money是运行文件全局名称空间中的money,而第一句print(md.money)中的money是被导入的md文件全局空间中的money,两者不在同一个空间中,money = 1000不会解绑
def read1():
print('from read1')
md.read2()
调用md.read2()是模块文件md全局空间中的read2,函数体内部调用read1(),也是模块空间中的read1。运行文件中也加入了一个函数名read1,但是没有调用。
money = 999
md.change()
print(money) # 999
print(md.money) # 0
2.2 from...import...句式
from md import money
from md import read1
from md import read2
# 上述三行代码可以简写为:
from md import money, read1, read2
2.2.1 底层原理
- 运行执行文件,产生执行文件的全局名称空间
- 运行md.py文件
- 产生导入文件的全局名称空间,把运行之后产生的名字都保存到导入文件的全局名称空间中
- 在执行文件的名称空间中产生对应的名字绑定模块名称空间中对应的名字
- 在执行文件中直接使用名字就可以访问名称空间中对应的名字
print(money)
read1()
read2()
# 指名道姓的导入
money = 666
print(money) # 666
导入模块文件from md import money语句之后,就会在运行全局空间产生一个money绑定到md空间中的(md.)money.赋值money = 666后之前的money——>md.money=1000的绑定结束,money重新与666绑定。
2.3 两者优缺点
import句式
* 由于使用模块名称空间中的名字都需要模块名点的方式才可以用
* 所以不会轻易的被执行文件中的名字替换掉
* 但是每次使用模块名称空间中的名字都必须使用模块名点才可以
from...import...句式
* 指名道姓的导入模块名称空间中需要使用的名字 不需要模块名点
* 但是容易跟执行文件中名字冲突
* 之后赋值会把模块空间中的值代替掉
三、导入文件的扩展用法
3.1 起别名
1.模块文件起别名
import mddddddddddddddddddddddddddddddddddddddd as md print(mddddddddddddddddddddddddddddddddddddddd.name)
# 起别名后:
import mddddddddddddddddddddddddddddddddddddddd as md
print(md.name)
# 使用后方便书写
2.给模块文件中的名字起别名
from mddddddddddddddddddddddddddddddddddddddd import namenamenamenamenamenamenamenamenamenamenamename print(namenamenamenamenamenamenamenamenamenamenamename)
# 起别名:
from mddddddddddddddddddddddddddddddddddddddd import namenamenamenamenamenamenamenamenamenamenamename as name
print(name)
3.2 多个模块导入
import time
import md
import os
import sys
# 推荐还是分开写好一些
如果模块功能相似度不高 推荐使用第一种 相似度高可以使用第二种
import time, md, os, sys # 等价于上面4行代码
3.3 通用导入
3.3.1 *的使用
from md import * # *默认是将模块名称空间中所有的名字导入
print(money)
read1()
read2()
change()
3.3.1 __all__的使用
all = ['名字1', '名字2'] 只针对*可以限制,只能拿all里面的名字(写在被导入文件中),all中只能是字符串类型
# 被导入文件中写入:
__all__ = ['money', 'read1']
# 执行文件中写入:
from md import *
print(money)
read1()
# 此时调用*,只能够调用money,read1
四、判断文件类型
- 判断当前文件是执行文件还是导入文件可以使用:name
__name__在不同的文件中,结果是不一样的:
* 在执行文件中,结果是 main(str类型)
* 在导入文件中,结果是:模块名
if __name__ == '__main__':
print('当前是执行文件')
上述脚本可以用来区分所在py文件内python代码的执行
快捷方式:main+tab键
使用场景
1. 模块开发阶段
2. 项目启动文件
def eat():
print('想干饭了')
def drink():
print('想喝水了')
if __name__ = '__main__':
eat()
drink()
# 只有该文件是执行文件时,才会执行eat()、drink()两个函数,如果该文件是被导入文件时,不会执行
五、循环导入
5.1 循环导入
两个文件之间彼此导入彼此并且相互使用各自名称空间中的名字,极容易报错。在实际工作中,坚决不能出现
# 运行文件:c3
import c1
# 被导入文件:c1
print('正在导入c1')
from c2 import y
x = 'c1'
# 被导入文件:c2
print('正在导入 c2')
from c1 import x
y = 'c2'
'''如果你的程序出现了循环导入,说明你的程序设计的不合理!!!!'''
在c1全局空间中还没有存入x='c1',就在c2中使用了x,产生错误:ImportError: cannot import name 'x'
5.2 如何解决循环导入问题
- 确保名字在使用之前就已经准备完毕
- 我们以后在编写代码的过程中应该尽可能避免出现循环导入(会浪费内存空间)
# 运行文件:c3
import c1
# 被导入文件:c1
print('正在导入c1')
x = 'c1'
from c2 import y
# 被导入文件:c2
print('正在导入 c2')
y = 'c2'
from c1 import x
六、模块的查找顺序(重要)
"""
1. 先从内存中查找(很少用到)
2. 再从内置模块中查找
3. 从环境变量中查找sys.path (********************************)
"""
6.1 内存
import m3
import time
time.sleep(15)
print(m3.name)
m3.func1()
先导入一个模块文件m3,执行time模块,在停顿的时间中,把存在硬盘里的m3.py删掉,看是否还能够执行后面的语句
>>> jason
>>> from func1
可以执行,说明模块查找先从内存中查找
结束后再次运行,会报错。硬盘中的m3.py已经删除,再次运行第一步(import m3),内存到硬盘中寻找就找不到m3文件.
6.2 内置
建一个py文件,命名为time.py。文件中输入:
name = 'kevin'
在运行文件(05 模块的查找顺序.py)中输入:
import time
print(time)
print(time.time)
>>> 输出内容是:
>>> 1678180721.0968993
>>> '''AttributeError: module 'time' has no attribute 'name''''
会识别内置中的time模块,不能识别新建的time.py文件。
一定要注意以后的文件名命名坚决不能跟内置模块名重名(*********************)
6.3 从环境变量中查找sys.path (重点)
6.3.1 当文件不在根目录中
1.打印sys.path
import sys
print(sys.path)
# 返回路径,以列表形式
"""
sys.path中第一个元素的路径永远是当前文件所在的路径'D:\\python25\\day18'
——>转义的方式。表示这里\\是一个普通\字符,不容易出错
"""
2.新建一个模块m3,在运行文件中导入
import m3
# 直接写m3即可,因为m3跟运行文件是同一级别文件
3.新建一个aaa文件夹,把m3放入
再写 import m3,就不能导入了,运行文件会出错,有什么解决方式吗?
6.3.2 解决方式:
方式1:将aaa路径添加到环境变量中
import sys
sys.path.append(r'D:\python25\day18\aaa')
import m3 # 会有红波浪线但是可以执行
方式2:
from aaa import m3
不同使用:
# 1.aaa下新建一个bbb文件,把m3放入
from aaa.bbb import m3
# 2.在m3中导入md模块,方法:
import md # 可以找到(是在环境变量中找到的)
6.3.3 总结
- 把模块所在的路径添加到环境变量中
import sys
sys.path.append('路径')
sys.path.insert(0,'路径') - 执行文件位置同级别的文件下的文件,可以用句点符。模块1就是执行文件位置同级别的文件
from 模块名1.模块名2 import 模块3