Python 的 import 是怎么工作的?
时间:2023-05-16 06:30
你好,我是 somenzz,可以叫我征哥。 Python 的 import 是非常直观的,但即使这样,有时候你会发现,明明包就在那里,我们仍会遇到 ModuleNotFoundError,明明相对路径非常正确,就是报错 导入同一个目录的模块和不同的目录的模块是完全不同的,本文通过分析使用 import 经常遇到的一些问题,来帮助你轻松搞定 import ,据此,你可以轻松创建属于自己的包。 模块与包的关系,可以类比文件和目录,模块就是文件。 Python 文档中这样描述,一个 Python 文件就是一个模块,Python 的文件名(不带后缀.py)就是模块名。 一个 module 可以包含变量、函数和类,它们是该 module 定义的命名空间的一部分,因此变量的命名问题不是问题,因为两个不同的模块可以有同名的变量、函数和类。 模块与包的关系,可以类比文件和目录,包就是目录。 package 里面可以有 module,也可以有子包(sub-package)。一个模块定义一个命名空间,以便变量、函数和类可以在两个不同的模块中具有相同的名称,同样的,一个包对其组成的包和模块做同样的事情,可以通过点号访问主包中的模块和包。 一个基本的 package 可以包含 sub-package、modules、__init__.py(Python 3.3 之后非必需)、setup.py。一个可能的 package 结构如下所示: 而 setup.py 存在于你的 package 所在的主目录中,包含配置信息,如所需的依赖项、脚本和子包。你还可以指定有关 package 的元数据,例如 package 的名称、作者、描述等。 setup.py 是 pip 用来安装你的包的文件。 先举一个简单的例子,比如说同一个目录有两个文件,file1.py 和 file2.py,内容很简单,就打印各自的文件名,不同的是 file2.py 里面 import 了 file1: 运行 file2.py 可以得到下面的结果: 可以看出: 我们还要知道 import 的搜索顺序,只需要记住一点,那就是 import 会去 sys.path 里面搜索。 比如我在 file2.py 的末尾添加一行代码:import sys; print(sys.path) 就可以打印 import 的搜索路径: 可以看出 sys.path 的顺序: 关于 sys.path 需要你注意的是: 一旦模块或包被找到,就会执行该模块或包。如果包里面有初始化文件 __init__.py,导入的时候,会先执行 __init__.py。 然后要导入的项目就添加到了其命名空间内,我们可以通过 xx.yy 的方式来使用。 先看看什么是绝对导入,所谓绝对导入就是这样的形式: 这样的方式很直观, import 会去 sys.path 查找就行了,如果遇到了 ModuleNotFoundError,思考一下为什么 sys.path 没有我们要导入的包,或者手动把这个包的路径插入到 sys.path 中去。 再看看什么是相对导入,所谓相对导入就是这样的形式: 也就是说相对路径中有个 . 号,用来表明要导入的模块或当前的包的相对位置。 举个例子,我们 pythonimportexample 目录下新建一个目录 subpackage1,在 subpackage1 内新建两个文件 file3.py、file4.py。 内容如下: file3.py : file4.py: 只要我们直接运行 file4.py,那是一定会报错的: Python 提示我们: 也就是说相对导入不知道父包是谁,换句话说,这是一个子包,必须让父包来调用它,直接运行这个文件是不行的,即使你在 file4.py 的目录 subpackage1 同级的目录执行该文件也是不行的,见上图。 但是在 file4.py 的目录 subpackage1 同级的目录作为一个 module 来执行是可以的,如下图: 换句话说,我们把 subpackage1 作为一个包来让别人用,相对导入是可以的,比如说我们在目录 subpackage1 同级的目录新建一个 file5.py 的文件,内容如下: file5.py: from subpackage1 import file4。 然后,执行 python file5.py 可以看出,相对导入已经正常工作: 结论 先上一个图来看下目录及引用结构,方块的是目录,椭圆的是文件,曲线是引用: 其中 import_example 目录下有 setup.py 和 run.py run.py 导入了 file4、file5、file6。 file4 导入了 file3,file5 导入了 file3。 file6 导入了 file2,file2 导入了 file1。 现在我们来执行一下 run.py 看下效果: 可以看出所有相对导入都已正常工作,虽然 file3 被导入了两次,但只执行了一次,说明 Python 内部已经考虑了同一个包的多重导入问题。 自定义包就是让其他文件导入使用的,因此 pythonimportexample目录下都使用相对导入,源代码见: https://gitee.com/somenzz/code-example/tree/master/import_example 点阅读原文也可以直接访问。 这里还有一些自定义包的例子: 本文分享了什么是模块(module),什么是包(package),import 的搜索路径,也分享了相对导入和绝对导入的区别,最后举了一个非常实用的 import 例子,方便你构建自己的包。 以上就是Python 的 import 是怎么工作的?的详细内容,更多请关注Gxl网其它相关文章!ImportError: attempted relative import with no known parent package
1.什么是模块(module),什么是包(package)
模块(module)
包(package)
2.import 时发生了什么
#file1.pyprint("This is file1.py")#file2.pyprint("This is file2.py")import file1
❯ python file2.pyThis is file2.pyThis is file1.py
3.什么时候用相对导入,什么时候用绝对导入
import aaimport aa.bbfrom aa import bb
from . import aafrom .aa import bbfrom .. import yy
print("This is file3.py")
from . import file3print("This is file4.py")
ImportError: attempted relative import with no known parent package
4.一个自定义包的例子
最后的话