解析Python3中的Import


Posted in Python onOctober 13, 2019

Python import的搜索路径

import的搜索路径为:

  • 搜索「内置模块」(built-in module)
  • 搜索 sys.path 中的路径
  • 而sys.path在初始化时,又会按照顺序添加以下路径:

foo.py 所在目录(如果是软链接,那么是真正的 foo.py 所在目录)或当前目录;

环境变量 PYTHONPATH中列出的目录(类似环境变量 PATH,由用户定义,默认为空);
site 模块被 import 时添加的路径1(site 会在运行时被自动 import)。

import site 所添加的路径一般是 XXX/site-packages。如果懒得记 sys.path 的初始化过程,可以简单的认为 import 的查找顺序是:

内置模块

.py 文件所在目录
pip 或 easy_install 安装的包

绝对导入和相对导入

绝对导入和相对导入的关系可以类比绝对路径和相对路径。

绝对导入的格式为:

import A.B
或
from A import B

相对导入格式为:

from . import B
或
from ..A import B

其中,点号.代表当前模块,..代表上层模块,…代表上上层模块,依次类推。

模块的执行方式

模块的执行可以有两种方式:直接执行和以模块执行,即:

python example/foo.py
或
python -m example.foo

注意,以模块执行时,一定要有包的概念,即example一定是个包,而foo是这个包下的模块,这样才能顺利执行。

包和模块

模块: 一个 .py 文件就是一个模块(module)

包: init .py 文件所在目录就是包(package)

各种情形测试

模块直接导入

即模块所在的目录都不是一个包结构,各个模块都是独立的,比如以下的目录结构:

D:\LEARN\IMPORT_TEST\TEST1
├─pack1
│  modu1.py
└─pack2
  modu2.py

modu1.py中的内容为:

import sys
sys.path.append("D:\\learn\\import_test\\TEST1\\pack2")
from modu2 import hello2
hello2()

modu2.py中的内容为:

def hello2():
 print("hello, I am module 2")

注意在modu1中一定加上sys.path.append那部分内容,即根据上面的描述,一定要让modu1能找到modu2才行,否则就会出现如下错误:

ModuleNotFoundError: No module named 'modu2'

此时进入pack1目录下,以直接执行或模块执行的方式都可以顺利输出。

包外导入

将上面两个模块所在的目录都变为包结构,即:

D:\LEARN\IMPORT_TEST\TEST2
├─pack1
│  modu1.py
│  __init__.py
└─pack2
  modu2.py
  __init__.py

此时也能顺利执行,同时比上面非包结构的多出来一条执行方式,即:

python -m pack1.modu1

即以包名+模块名的方式执行。

上面两种情形,即模块与模块、包与包都是相互独立的关系,也就没有相对导入的意义。

如果是在一个包内的不同模块的导入,那么最自然的就是使用相对导入。

包内相对导入

D:\LEARN\IMPORT_TEST\Test3
│ __init__.py
│
├─pack1
│  modu1.py
│  __init__.py
│
└─pack2
  modu2.py
  __init__.py

此时modu1.py中的内容为:

from ..pack2.modu2 import hello2
hello2()

即将sys.path.append去掉,因为是在一个包内相互引用,此时这样写没有意义。

此时正确运行的方式是进入Test3上一层的文件夹,然后:

python -m Test3.pack1.modu1

即明确地告诉解释器模块的层次结构。

而如果采用直接运行的方式,比如:

python Test3\pack1\modu1.py

就会报如下错误:

ValueError: attempted relative import beyond top-level package

这是因为,相对导入使用模块的 name (这里的name和下面的main都是有两个下划线的,但是网页显示不出来。。)属性来决定模块在包结构中的位置。当 name 属性不包含包信息(i.e. 没有用'.'表示的层次结构,比如' main ‘),则相对导入将模块解析为顶层模块,而不管模块在文件系统中的实际位置。这里模块被直接运行,则它自己为顶层模块,不存在层次结构,所以找不到其他的相对路径。

因此,直接运行带有相对导入的模块是不行的,需要通过模块运行的方式,将包结构明确告诉它才行。

这个原理也适用于下面这种错误,比如将modu2移动到pack1中,即与modu1在同一个目录下,然后将modu1的内容改为这样的相对引用:

from .modu2 import hello2
hello2()

此时使用模块执行的方式没有问题,如果还是想尝试直接运行,那么就会出现:

ModuleNotFoundError: No module named '__main__.modu2'; '__main__' is not a package

原因就是此时没有包结构, main 也不是个包。

那么解决方法就是或者使用模块运行的方式运行,或者将它改成下面的绝对导入的方式就可以直接运行。

包内绝对导入

那么,如果将modu1.py中的内容改为绝对导入,即:

from Test3.pack2.modu2 import hello2
hello2()

此时正确运行方式也是进入Test3上一层文件夹,然后使用模块执行的方式运行:

python -m Test3.pack1.modu1

如果此时采用直接运行的方式:

python Test3\pack1\modu1.py

那么就会报错:

ModuleNotFoundError: No module named 'Test3'

这主要是因为Test3没有被找到,即按照第一部分所说,Test3没有在import的搜索路径中。所以,只要将它加入进去即可,比如:

set PYTHONPATH=D:\learn\import_test\

此时再直接运行就没有问题了。

总结

以上所述是小编给大家介绍的Python3中的Import理解,希望对大家有所帮助!

Python 相关文章推荐
Python搭建APNS苹果推送通知推送服务的相关模块使用指南
Jun 02 Python
恢复百度云盘本地误删的文件脚本(简单方法)
Oct 21 Python
Python基于win32ui模块创建弹出式菜单示例
May 09 Python
Django Rest framework之权限的实现示例
Dec 17 Python
在Pycharm中执行scrapy命令的方法
Jan 16 Python
华为2019校招笔试题之处理字符串(python版)
Jun 25 Python
Python使用numpy模块实现矩阵和列表的连接操作方法
Jun 26 Python
Django框架中序列化和反序列化的例子
Aug 06 Python
3行Python代码实现图像照片抠图和换底色的方法
Oct 10 Python
Python全局锁中如何合理运用多线程(多进程)
Nov 06 Python
python写文件时覆盖原来的实例方法
Jul 22 Python
Python 如何实现文件自动去重
Jun 02 Python
Python英文文章词频统计(14份剑桥真题词频统计)
Oct 13 #Python
Python 转换RGB颜色值的示例代码
Oct 13 #Python
Django中自定义查询对象的具体使用
Oct 13 #Python
PyCharm导入python项目并配置虚拟环境的教程详解
Oct 13 #Python
Python 用三行代码提取PDF表格数据
Oct 13 #Python
Python3离线安装Requests模块问题
Oct 13 #Python
详解使用Python下载文件的几种方法
Oct 13 #Python
You might like
PHP中设置时区方法小结
2012/06/03 PHP
Codeigniter出现错误提示Error with CACHE directory的解决方案
2014/06/12 PHP
[原创]smarty简单模板变量输出方法
2016/07/09 PHP
利用Dojo和JSON建立无限级AJAX动态加载的功能模块树
2007/03/24 Javascript
一段效率很高的for循环语句使用方法
2007/08/13 Javascript
DOM Scripting中的图片切换[兼容Firefox]
2010/06/12 Javascript
JS比较2个日期间隔的示例代码
2014/04/15 Javascript
jquery ajax局部加载方法详解(实现代码)
2016/05/12 Javascript
详解JavaScript 中getElementsByName在IE中的注意事项
2017/02/21 Javascript
微信小程序实现带刻度尺滑块功能
2017/03/29 Javascript
angular指令笔记ng-options的使用方法
2017/09/18 Javascript
微信小程序使用picker实现时间和日期选择框功能【附源码下载】
2017/12/11 Javascript
Nodejs下使用gm圆形裁剪并合成图片的示例
2018/02/22 NodeJs
jQuery实现监听下拉框选中内容发生改变操作示例
2018/07/13 jQuery
小程序实现选择题选择效果
2018/11/04 Javascript
用python删除java文件头上版权信息的方法
2014/07/31 Python
Python生成密码库功能示例
2017/05/23 Python
Python自动化运维之IP地址处理模块详解
2017/12/10 Python
Python 实现淘宝秒杀的示例代码
2018/01/02 Python
Python学习笔记之lambda表达式用法详解
2019/08/08 Python
python实现网站微信登录的示例代码
2019/09/18 Python
简单了解Python读取大文件代码实例
2019/12/18 Python
django迁移文件migrations的实现
2020/03/31 Python
python def 定义函数,调用函数方式
2020/06/02 Python
python3 通过 pybind11 使用Eigen加速代码的步骤详解
2020/12/07 Python
世界上最好的足球商店:Unisport
2019/03/02 全球购物
aden + anais英国官网:美国婴儿贴身用品品牌
2019/09/08 全球购物
澳大利亚在线购买葡萄酒:The Wine Collective
2020/02/20 全球购物
Monki官网:斯堪的纳维亚的独立时尚品牌
2020/11/09 全球购物
C#中的验证控件有几种
2014/03/08 面试题
数据库测试通常都包括哪些方面
2015/11/30 面试题
大学班级学风建设方案
2014/05/01 职场文书
优秀毕业生的求职信
2014/07/21 职场文书
2015年幼儿园卫生保健工作总结
2015/05/12 职场文书
JavaScript函数柯里化
2021/11/07 Javascript
浅谈音视频 pts dts基本概念及理解
2022/08/05 数码科技