目录
当我们导入自定义库时,需要注意python中关于包导入以及包内导入的知识。对于python2和3对于包内导入有着不一样的方式。
包导入
python的包导入需要在包内部有__init__.py文件,同样的,包内如果还有包,那么要导入包内的包,包内包也需要有__init__.py文件,以此类推。__init__.py文件在包被导入时会被执行,并且执行之后该文件产生一个命名空间传给被导入的包变量,命名空间中的元素就是__init__.py中的模块变量,所以__init__.py文件起到一个包初始化的作用。__init__.py文件是可以为空的,当__init__.py为空时,那么命名空间为空,即被导入包也就没有可访问的属性,但是这依然不影响包中包的显示导入,只是无法直接通过一级被导入包变量直接通过点号访问二级包或者模块而已。如下示例代码,对应两种包导入方式,假设包dir1里面有一个子包dir2,且都有__init__.py文件。现在如果dir1里面的__init__.py文件为空,那么dir1就无法通过点号访问dir2,所以方式1的导入是不可行的,只有当dir1中的__init__.py里面导入了dir2,这时dir1可以直接访问dir2,才可以通过方式1导入module1。但是只要__init__.py文件存在,不论其是否为空,方式2的导入方式都是可以的。不管怎样,只有被初始化到__init__.py中的模块或者包才可以被直接点号访问,无论是第几级的包,都需要在相应级别的包内被初始化到__init__.py文件中。
# 方式1
from dir1.dir2 import module1
# 方式2
from dir1 import dir2
from dir2 import module1
包内导入
包内导入指的是包内文件的相互导入,不涉及包外的文件。包内导入在python2和3中是不一样的。在python2中,当包内的一个文件进行包内导入时,模块的搜索路径和包外导入是一样的,即首先会从脚本自己所在的目录下开始搜索,所以可以直接用import modulename的方式导入同级目录下的模块或者包;但是在python3中,对于包内导入,只支持包内的相对导入,即不再进行首先同级目录下的搜索。所以如果要在python3中包内导入的话,必须使用相对导入,即from . import modulename的方式,或者from dir2 import modulename;如果直接在python3的包内导入中使用import modulename方式,会报错找不到模块。
利用__init__.py初始化
利用__init__.py文件进行初始化实际上主要就是进行一些自定义初始化行为,更多的是在该文件中导入模块,给被导入包变量构造命名空间。由于在该文件中的导入属于包内导入,因此遵守包内导入的规则。此外需要额外注意的一点是,需要注意几个变量,__all__变量和__path__变量。可以将需要导入的包或模块名称添加到__all__列表中,然后from . import *语句会导入__all__变量中的元素,所以对于使用星号*的导入方式,其实际上导入的是__all__变量中的元素,__all__变量需要自定义,默认情况下改变量不存在,所以星号*导入方式不会起作用,所以星号导入方式应该和__all__变量结合起来使用,或者不使用星号*导入方式,使用from . import modulename的精确导入方式,逐一导入需要可以直接访问的模块。__path__变量默认是只有一个元素的列表,该元素是脚本所在的路径,所以相对导入时,python会通过该变量获取路径实现导入。