当前位置: 首页 > 科技观察

Python的导入是如何工作的?

时间:2023-03-13 07:02:26 科技观察

大家好,我是somenzz,你们可以叫我郑哥。Python的import很直观,但即便如此,有时候你会发现包在,我们还是会遇到ModuleNotFoundError,明明是相对路径很正确,是错误ImportError:attemptedrelativeimportwithnoknownparentpackageimportModulesin同一目录与不同目录中的模块完全不同。本文通过分析import使用中经常遇到的一些问题,帮助您轻松搞定import。基于此,您可以轻松创建自己的包。1、什么是模块,什么是包?模块和包的关系可以类比为文件和目录,模块就是文件。如Python文档所述,一个Python文件就是一个模块,Python文件名(不带.py后缀)就是模块名。一个模块可以包含属于该模块定义的命名空间的一部分的变量、函数和类,因此变量的命名不是问题,因为两个不同的模块可以具有同名的变量、函数和类。包模块和包的关系可以类比为文件和目录,包就是目录。包中可以有模块或子包。一个模块定义了一个命名空间,这样变量、函数和类可以在两个不同的模块中具有相同的名称,同样,一个包对其构成的包和模块也是如此,主包可以通过.一个基本包可以包含子包、模块、__init__.py(Python3.3之后不需要)、setup.py。一个可能的包结构如下所示:而setup.py位于包所在的主目录中,并包含配置信息,例如所需的依赖项、脚本和子包。您还可以指定有关包的元数据,例如包的名称、作者、描述等。setup.py是pip用于安装包的文件。2.导入时发生了什么?让我举一个简单的例子。比如同一个目录下有两个文件file1.py和file2.py。内容很简单,打印了各自的文件名。不同的是在file2.py中importfile1:#file1.pyprint("Thisisfile1.py")#file2.pyprint("Thisisfile2.py")importfile1运行file2.py得到如下结果:?pythonfile2.py这是file2。py这个是file1.py可以看出:import很直观,谁用谁import谁谁。import语句只是一个普通的语句,可以放在任何地方。当一个文件被导入时,它被执行并且它里面的类或对象被添加到它的命名空间中。我们还需要知道import的搜索顺序,只要记住import会在sys.path中搜索。比如我在file2.py的末尾添加一行代码:importsys;print(sys.path)打印导入搜索路径:可以看到sys.path的顺序:先搜索脚本执行的路径第三方标准库site-packages库需要注意sys.path:in解释器环境,sys.path[0]是解释器启动的路径''sys.path不依赖于当前程序的工作路径-os.getcwd(),只依赖于第一个脚本所在的路径located:如果一个模块导入了另一个模块,而这个模块又导入了另一个模块,那么第一个模块的sys.path就是解释器搜索第二个import语句的位置。一旦找到模块或包,就会执行它。如果包中有初始化文件__init__.py,导入时会先执行__init__.py。然后将要导入的项目添加到它的命名空间中,我们就可以通过xx.yy来使用了。3、什么时候用相对导入什么时候用绝对导入先看看什么是绝对导入,所谓绝对导入就是这样的形式:importaaimportaa.bbfromaaimportbb这种方式很直观,import会去sys.path找到就可以了,如果遇到ModuleNotFoundError,想想为什么sys.path中没有我们要导入的包,或者手动把这个包的路径插入到sys.path中。让我们来看看什么是相对导入。所谓相对导入就是这种形式:from。importaafrom.aaimportbbfrom..importyy也就是说,有一个.在相对路径中,用于指示要导入的模块或当前包的相对位置。比如我们在pythonimportexample目录下新建目录subpackage1,在subpackage1新建两个文件file3.py和file4.py。内容如下:file3.py:print("Thisisfile3.py")file4.py:from.importfile3print("Thisisfile4.py")只要我们直接运行file4.py,肯定会报错:PythonPromptus:ImportError:attemptedrelativeimportwithnoknownparentpackage意思是相对导入没有知道父包是谁。也就是说,这是一个必须被父包调用的子包。这个文件是不能直接运行的,即使在file4.py目录下执行subpackage1同级目录下的文件也是不行的,见上图。但是在file4.py目录下,subpackage1和同级目录可以作为一个模块来执行,如下图:也就是说,我们把subpackage1作为一个包给别人使用,相对导入是可以的。比如我们在目录subpackage1的同级目录下新建文件file5.py,内容如下:file5.py:fromsubpackage1importfile4。然后,执行pythonfile5.py,可以看到相对导入已经正常了:结论如果直接作为脚本文件运行,使用绝对导入。如果是作为其他文件导入的模块,使用相对导入。4.一个自定义包的例子首先看上一张图中的目录和引用结构。正方形是目录,椭圆是文件,曲线是引用:import_example目录下导入了setup.py和run.pyrun.py。文件4、文件5、文件6。file4导入file3,file5导入file3。file6导入file2,file2导入file1。现在我们执行run.py看看效果:可以看到所有的相对导入都正常了。file3虽然导入了两次,但只执行了一次,说明Python考虑了同一个包的多次导入。.自定义包是供其他文件导入使用,所以在pythonimportexample目录下使用相对导入。源码见:https://gitee.com/somenzz/code-example/tree/master/import_example点击阅读原文,也可直接访问。下面是一些自定义包的例子:dbinterface[1]transferfile[2]最后,这篇文章分享了什么是模块,什么是包,导入的搜索路径,也分享了相对导入和绝对导入最后一个很实用的给出了导入的例子,方便你自己构建包。