模块
1、什么是模块
常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py
的后缀。
但其实import加载的模块分为四个通用类别:
1 自定义模块:使用python编写的代码(.py文件)
2 第三方模块:已被编译为共享库或DLL的C或C++扩展
3 包:包好一组模块的包
4 python内置模块:使用C编写并链接到python解释器的内置模块
2、为什么使用模块
1、将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行
2、为了方便管理,我们通常将程序分成一个个的文件,除了当作脚本运行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用
3、如何使用模块
3.1 注意点
-
为了防止对同一模块的重复导入,python的优化手段是:
第一次导入后就将模块名加载到内存,以
my_module
为例后续的
import
语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句
sys.modules
中可以找到当前已经加载的模块 -
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间
3.2 首次导入模块时发生的事情
- 为模块文件
my_moudle.py
创建新的名称空间 - 在新创建的命名空间中执行模块中包含的代码
- 用模块文件名
my_moudle
创建名字来引用该命名空间
3.3 import 模块名
3.3.1
添加了模块名称空间的引用,等同于将模块源文件的名称空间带到当前文件名称空间中,使用时必须是模块名.名字
的方式
3.3.2
为模块名起别名,相当于m1=1;m2=m1
import my_module as sm
print(sm.money)
3.3.3
在一行导入多个模块
import sys,os,re
3.4 from ... import ...
3.4.1
-
from
语句相当于import
,也会创建新的名称空间,但是将my_module
中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了from my_module import read1,read2
-
如果当前有重名
read1
或者read2
,那么会有覆盖效果接使用read1
和read2
就好了,执行时,仍然以my_module.py
文件全局名称空间
3.4.2
也支持as
from my_module import read1 as read
3.4.3
也支持导入多行
from my_module import read1,read2,money
3.4.4 from my_module import *
-
from my_module import *
把my_module中
所有的不是以下划线(_)开头的名字都导入到当前位置因为
*
你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字可读性极其的差,在交互式环境中导入时没有问题
-
在
my_module.py
中新增一行,限制from my_module import *
能导入的名称__all__=['money','read1'] #这样在另外一个文件中用from my_module import *就只能能导入列表中规定的两个名字
3.4.5 循环导入
模块mi
和m2
相互导入
此时可能会出现一种情况:
m1
从m2
导入的名称是在m2
中的导入mi
语句下面定义的
m2
从m1
导入的名称是在m1
中的导入m2
语句下面定义的
因而m1
和m2
中的导入语句都找不到目标名称,就像是陷入了循环一样,都不会执行下面的代码
解决办法:
1、在import
语句之前定义目标名称
2、在函数体内导入,因为函数只检测语法,不执行代码
3.4.6模块的加载与修改
- 每个模块只被导入一次,放入字典
sys.modules
中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块 - 删了
sys.modules
中的模块对象仍然可能被其他程序的组件所引用,因而不会被清除
3.5 把模块当作脚本运行
通过模块的全局变量__name__
来查看模块名:
- 当做脚本运行:
__name__
等于'__main__'
- 当做模块导入:
__name__
= 模块名
作用:用来控制.py
文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':
3.6 模块搜索路径
内存中已经加载的模块->内置模块->sys.path
路径中包含的模块
-
python解释器在启动时会自动加载一些模块,可以使用
sys.modules
查看 -
在初始化后,python程序可以修改
sys.path
,路径放到前面的优先于标准库被加载import sys sys.path.append('/a/b/c/d') sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索
3.7 编译python文件
为了提高加载模块的速度,python解释器会在__pycache__
目录中下缓存每个模块编译后的版本
python解释器在以下两种情况下不检测缓存:
-
在命令行中被直接导入模块,每次导入都会重新编译,并且不会存储编译后的结果
python -m my_module.py
-
源文件不存在,那么缓存的结果也不会被使用,如果想在没有源文件的情况下来使用编译后的结果,则编译后的结果必须在源目录下
3.8 dir()函数
内建函数dir()
是用来查找模块中定义的名字,返回一个有序字符串列表
import my_module
dir(my_module)