python中的import绝对导入与相对导入详解

 更新时间:2023年11月03日 10:03:27   作者:惊瑟  
这篇文章主要介绍了python中的import绝对导入与相对导入详解,在使用python做一些简单项目时,import一般不会出现问题,但项目结构复杂时,import可能发生报错,需要的朋友可以参考下

前言

在使用python做一些简单项目时,import一般不会出现问题,但项目结构复杂时,import可能发生报错。

最常见的错误是:ImportError: attempted relative import with no known parent package,要弄清楚问题本质,就需要了解import的工作机制了。

众所周知,import分为绝对导入和相对导入,两者的唯一区别就是是否使用了"." 为一探究竟,构建以下项目目录:

imp_test
├── entrance1.py
├── pakg1
│   ├── __init__.py
│   ├── module1.py
│   ├── module2.py
│   └── pakg1_1
│       └── __init__.py
└── pakg2
    └── __init__.py

一、绝对导入

先明确下,python中modules的概念并不统一,官方文档中的modules有时候指的是package,有时候指的是py文件,为了避免歧义,本文中module特指py文件,modules指“py文件以及包”。 形式如import XXX或from XXX import a,b 都是绝对导入。比如在module1.py中导入module2.py中的内容:from module2 import v2。 当执行绝对导入时,解释器做了以下这些事情:

查找built-in modules(内置模块)。内置模块是python解释器的一部分,用C语言编写,常见的有os time sys json;

查找sys.path包含的目录,包括:

  • 启动文件所在的目录
  • 当前项目的顶级目录(注意:前提是使用IDE,在命令行直接import没有这个目录,可以理解为,在新建项目时IDE自动将项目目录添加到了sys.path中了)
  • 当前解释器lib目录,主要是第三方包的安装目录

因此可以得出结论:绝对导入时,启动文件所在的目录下以及项目顶级目录下的包或py文件可以直接导入(此时IDE可以自动补全)。值得注意的是,当项目中涉及多个层级目录下的py文件或模块的互相导入,所有py文件的sys.path都是一样的,绝对导入的搜索目录针对的都是启动文件。 可以测试,当启动文件为pakg1.module1.py,在pakg1.module1.py中执行绝对导入,都没问题:

#pakg1.module1.py
import pakg1_1 # 当前目录下的包
import pakg2 # 顶层目录下的包
import module2 # py文件

但是当启动文件为entrance1.py时,在entrance1.py执行绝对导入:

#entrance1.py
import pakg1.module1

就会提示在pakg1.module1.py中import module2报错:

ModuleNotFoundError: No module named 'module2'

原因如上所述,启动文件为entrance1.py时,module2并未在其搜索目录中。

二、相对导入

带".“的导入是相对导入,如:from .XXX import a,b,要理解相对导入,关键在于搞明白”."是什么含义。 在pakg1.module1.py执行相对导入:

#module1.py
print('pakg1.module1 __name__ is:',__name__)
from .module2 import v2
print(v2)

并启动pakg1.module1.py,得到报错:

ImportError: attempted relative import with no known parent package
pakg1.module1 __name__ is: __main__

要理解"."的含义,关键在于理解python的__name__属性:事实上python所有对象都有该属性,包括包和py文件。对于py文件,这个属性不是一成不变的:

  • 当其是启动文件时,该文件的__name__ = "__main__";
  • 当其不是启动文件时,__name__ = pakg_name.module_name,其中pakg_name从顶层目录的包开始算起,有多层则以此类推;

而相对导入中的".“则指的是,该文件的__name__属性去掉最后的文件名前面的部分,即该文件的“父包”,当该文件是启动文件时,由于__name__ = "__main__",此时“父包”为空,故会报错no known parent package。 事实上,python的modules还有一个属性__package__,官方文档解释如下:

在这里插入图片描述

从以上文字我们可以了解到:对于包来讲,__package__ == __name__,而对于py文件来讲,__package__则代表其父包,并且对于在项目顶层目录的py文件(对于启动文件,不管实际目录怎样,都认为它是顶层文件),该属性为空。因此我们可以认为某文件中相对导入的”.",指的就是该文件的__package__属性。

三、结论

弄明白原理后,在实际项目中涉及到import,可以总结以下几条原则:

  • 如果项目层级不是特别深,而结构预计不会做很大调整,最保险的导入方式是:统统使用绝对导入,并且从项目顶层包开始引入;
  • 反之,当项目层级很深,而结构可能面临调整时,可以使用相对导入,但需要保证该文件不是启动文件;
  • 对于项目顶层文件,无论其是不是启动文件,都不要使用相对导入,因为顶层文件再上层是项目目录,没有父包了,即__package__ = ''。

四、关于__init__

为什么每个包要有一个__init__?首先是因为它可以标志这是一个包,可以被import;其次,在实际项目中,我们需要对外暴露的内容更多的是函数、类或变量,如果要导入这些对象,就需要from pakg_name.module_name import a,b,c,可能略显冗长,而如果提前在包的__init__中将要暴露的对象导入,这些对象将属于“包的子集”,导入时只需要精确到包就行了,即from pakg_name import a,b,c,除此之外,使用__all__还可以约束该包要暴露的内容,有“白名单”效果。因此在__init__明确每个包要暴露的对象是很好的习惯。

到此这篇关于python中的import绝对导入与相对导入详解的文章就介绍到这了,更多相关python中的import内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python实战之画哆啦A梦(超详细步骤)

    Python实战之画哆啦A梦(超详细步骤)

    这篇文章主要介绍了Python实战之画哆啦A梦(超详细步骤),文中有非常详细的代码示例,对正在学习python的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • 容易被忽略的Python内置类型

    容易被忽略的Python内置类型

    这篇文章主要介绍了容易被忽略的Python内置类型,帮助大家更好的理解和学习python,感兴趣的朋友可以了解下
    2020-09-09
  • Python中typing模块与类型注解的使用方法

    Python中typing模块与类型注解的使用方法

    这篇文章主要给大家介绍了关于Python中typing模块与类型注解的使用方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • Python3 用matplotlib绘制sigmoid函数的案例

    Python3 用matplotlib绘制sigmoid函数的案例

    这篇文章主要介绍了Python3 用matplotlib绘制sigmoid函数的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Python常问的100个面试问题汇总(下篇)

    Python常问的100个面试问题汇总(下篇)

    这篇文章主要介绍了Python常问的100个面试问题汇总(下篇),文章内容详细,简单易懂,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2023-01-01
  • python 进阶学习之python装饰器小结

    python 进阶学习之python装饰器小结

    这篇文章主要介绍了python 进阶学习之python装饰器小结,本文通过场景分析给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Python练习之操作SQLite数据库

    Python练习之操作SQLite数据库

    这篇文章主要介绍了Python练习之操作SQLite数据库,主要通过三个问题如何创建SQLite数据库?如何向SQLite表中插入数据?如何查询SQLite表中的数据?展开文章主题详情,需要的朋友可以参考一下
    2022-06-06
  • Python使用正则表达式报错:nothing to repeat at position 0的解决方案

    Python使用正则表达式报错:nothing to repeat at position 0的解决方案

    今天在使用python 正则模块匹配字符串时遇到了这个问题,分享给大家,这篇文章主要给大家介绍了关于Python使用正则表达式报错nothing to repeat at position 0的解决方案,需要的朋友可以参考下
    2023-03-03
  • Python 实现驱动AI机器人

    Python 实现驱动AI机器人

    这篇文章主要介绍了Python 实现驱动AI机器人,下文围绕利用Python 实现驱动AI机器人的相关资料展开内容,需要的小伙伴可以参考一下
    2022-02-02
  • python中导入 train_test_split提示错误的解决

    python中导入 train_test_split提示错误的解决

    这篇文章主要介绍了python中导入 train_test_split提示错误的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06

最新评论