解析Python3中的Import
作者:programming 发布时间:2023-01-10 05:11:47
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理解,希望对大家有所帮助!
来源:http://qixinbo.info/2019/10/13/python-import/
![](https://www.aspxhome.com/images/zang.png)
![](https://www.aspxhome.com/images/jiucuo.png)
猜你喜欢
- 上午在分析索引的使用情况,想看一下数据库什么时候启动的,确保统计的数据没有问题,可以使用下面三种方法查询:--2008及之后版本才有SELE
- 本文实例讲述了C#创建数据库及导入sql脚本的方法。分享给大家供大家参考,具体如下:C#创建数据库:/// <summary>/
- 前言我是一个半路出家的PHP程序员,到目前为止,不算在培训班学习的时间,已经写代码整整两年了。可能由于工作业务的原因,在这两年中我没有用到过
- 下面我们就分别讲述,虽然说的是Insert语句, 但是Select、Update、Delete语句都是一样的。 假如有下述表格:
- max() 方法返回其参数最大值:最接近正无穷大的值。语法以下是max()方法的语法:max( x, y, z, .... )参
- 前言Golang中当程序发生致命异常时(比如数组下标越界,注意这里的异常并不是error),Golang程序会panic(运行时恐慌)。当程
- 一个js用星投票的例子,不是常见的图片版,当然你如果会点js代码的话应该可以改为更加美观的图片投票,原理都一样。本程序只演示了读取星的个数,
- 一、前言本次安装tensorflow是基于Python的,安装Python的过程不做说明(既然决定按,Python肯定要先了解啊):本次教程
- 我就废话不多说了,大家还是直接看代码吧~import tensorflow as tfn1 = tf.constant(2)n2 = tf.
- 1.简介介绍-网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息
- 实例如下所示:import osos.chdir("G:\Python1\Lib\site-packages\pytesser&q
- 前言selenium处理文件上传大致会有两种情况,一种是文件上传使用的是input标签元素,即<input type="fi
- 我第一次接触爬虫这东西是在今年的5月份,当时写了一个博客搜索引擎,所用到的爬虫也挺智能的,起码比电影来了这个站用到的爬虫水平高多了!回到用P
- 这方面我还是一个freshman,不过看了一些文章,经过一些实践后也算是有了一些想法。希望如果有这方面的前辈路过的话,能不吝指教。首先,作为
- 需求场景:使用sqlalchmy从现有的表中获取数据(不是自己建表)。百度了一下,网上都是使用sqlalchemy自己先创建表,然后导入数据
- 前言sched是Python的内置模块,用于事件调度,可在安全的在多线程环境中轻松实现定时任务。sched是一种调度(延时处理机制)。sch
- 前言可能很多小伙伴会因为pycharm全是英文而烦恼吧,本博主呢也是一个英语刚过四级的小白,深知大家的难处,所以会奉上最详细的修改中文的教程
- 一、理解装饰器所有东西都是对象(函数可以当做对象传递)由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。de
- 本文实例讲述了Python实现查找两个字典相同点的方法。分享给大家供大家参考,具体如下:问题:寻找两个字典中间相同的地方(相同的键、相同的值
- 在工作中,我们经常需要从命令行当中解析出指定的参数,而 Python 也提供了相应的标准库来做这件事情,比如 sys, optparse,