python——包、模块
包、模块的概念
python中,将文件夹视为一个包,将文件夹(包)的一个文件视为一个模块,一个包下面,可以有多个模块,而每一个模块内部可以有多个变量、类、函数。
如果要将一个文件夹作为“包”,那么需要在这个文件夹的下一级目录下创建一个文件名为__init__.py的文件。比如,我有一个p1文件夹,我要将这个文件夹作为一个包,那么我就在p1文件夹下创建一个__init__.py问文件即可。这个__init__.py是一个比较特殊的文件,不仅标志着这个所在目录为一个包,而且,当这个包或者这个包中的模块被其他文件导入的时候,会首先运行这个__init__.py文件。
在导入一个模块的时候,会将这个模块(文件)执行一次。
包可以嵌套,即,文件夹(包)内部除了文件(模块),还可以有文件夹(包),同样需要遵守上面这个规则。
下面是一个项目的目录结构:
project |—— p1 |—— __init__.py |—— m1.py |—— son |—— __init__.py |—— m1.py |—— index.py |—— p2 |—— __init__.py |—— m1.py |—— main.py
上面这个结构中,project有两个包p1和p2,分别有自己的模块m1,虽然模块名称是一样的,但是因为路径不同,所以,模块是不同的。同时p1包中,还一个子包son,son包中也有一个模块m1。
导入模块
使用import关键字,格式如下:
import package.module
如果要导入本package中的module,那么可以省略package。
在main.py中要使用project下的p1和p2包的模块,方法如下:
#main.py import p1.m1 print(p1.m1.p1_m1) import p1.son.m1 print(p1.son.m1.p1_son_m1) import p2.m1 print(p2.m1.p2_m1)
p1目录下的index.py要想使用p1包下的模块时,方法如下:
import m1 #导入的是p1.m1模块,此时不要写p1.m1,因为index.py在p1包内 print(m1.p1_m1) import son.m1 #导入的是p1.son.m1模块 print(son.m1.p1_son_m1)
如果p1目录下的index.py要想导入p2包下的m1模块,方法如下:
设置模块别名
上面可以看出,在导入模块的时候,有使用会因为包的目录层级较深,导致使用模块中的某些变量时,要写很长的路径,解决这个方法,可以在import的时候,加一个as,给模块设置一个别名。
#使用as关键字,给模块设置一个别名 import p1.m1 as p1m1 print(p1m1.p1_m1) import p1.son.m1 as psm print(psm.p1_son_m1) import p2.m1 as p2m1 print(p2m1.p2_m1)
导入模块中的部分数据
有时候,我们在导入模块的时候,不需要导入某个模块中的所有内容,也许只需要其中的一个变量,那么我们可以使用from关键字:
# 格式 # from package.module import var|def|class from p1.m1 import p1_m1 print(p1_m1) # from package.module import var|def|class as alias from p1.m1 import p1_m1 as p print(p) # from package import module #导入某个模块 from p1 import m1 print(m1.p1_m1) #不需要再使用p1.m1
模块中指定导出的数据
有时候,如果我们想导入某个模块的某部分数据时,虽然可以使用from package.module import xxx,yyy,zzz....但是当数据过多,在import后面写出所有的数据,是很不现实的。
解决方法是在模块中为__all__变量赋值,值是一个list,内容为要导出的内容。
比如p1包下面的m1,内容如下:
__all__ = ["p1_m1"] #设置导出的内容只有p1_m1这个变量 p1_m1 = "bbbbbbbbb" p1_m11 = "czzzzzzz"
main.py中,尝试使用p1包下面的m1模块中的p1_m1,会成功,但是使用p1_m11时就会失败:
from p1.m1 import * print(p1_m1) #访问成功 print(p1_m11) #报错:name 'p1_m11' is not defined
导入某个包的所有模块
假设main.py需要导入p1包下面有m1.py和m2.py两个模块,那么我们可以使用下面方法导入p1下的所有模块:
from p1 import * print(m1.p1_m1) print(m2.p1_m2)
上面这个代码运行之后会报错,错误信息是:找不到m1,说明模块m1导入失败了,这是因为,需要在p1包的__init__.py中,修改__all__变量的值,内容就是要导出的模块名:
# 修改p1/__init__.py文件 print("从p1包中导出数据") __all__ = ["m1", "m2"]
然后main.py就可以正常运行了,并且首先输出内容“从p1包中导出数据”,表明再导入模块的时候,会先执行模块所在包目录下的__init__.py文件。
所以,只要在包下面的__init__.py中的__all__变量中指定要导出的模块名称即可。
导入python内置标准库
内置标准库有很多,比如sys,io...
__init__.py的功能
指定包导出的模块
就是前面在__init__.py中设置__all__变量的值,用来限制其他文件在导入该包中所有模块时,允许导入的模块。
合并要重复导入的包或者模块
经常有这种情况,我们一个文件夹下有很多python文件,并且每一个模块都需要引入很多相同的系统模块,比如都需要引入os,sys,io模块,有两种方法解决:
1、在每个文件中都使用import导入3个模块。简单直接,但是有点累,当导入的模块几十上百时,多个文件就会出现大量相同的代码(大量的import语句,每个文件的前100行全是import)。
2、在该文件夹下面,创建一个包,因为类型是包,所以包下一级会有一个__init__.py文件,所有重复导入的模块都在这里导入;然后在其他文件中,导入这个包即可,因为会首先执行__init__.py文件,也就将需要的模块导入了。
包、模块的导入导出注意事项
1、在导入包或者模块时,对同一个包或者模块重复的导入时,并不会报错,但最好不要重复导入,即使重复导入,模块代码也只会运行一次。
2、一个模块在导入其他模块的时候,避免出现“循环导入”的情况,比如下面这个情况:
#m1.py import m2 abc = m2.xyz #m2.py import m1 xyz = m1.abc
当其他文件导入m1或者m2时,就会出错。同样,执行m1或者m2时,也会报错,因为出现了循环导入的情况。