我正在使用以下程序。重要的是,假设这些程序所在的目录中有mymodule.py
个文件。
第一个:
exec('''import sys
import os
os.chdir('/')
sys.path = []
import mymodule''', {})
第二个:
import mymodule
exec('''import sys
import os
os.chdir('/')
sys.path = []
import mymodule''', {})
第一个片段按预期引发ImportError
(毕竟,mymodule所在的目录不在路径中)。然而,第二个片段没有,即使mymodule也不在它的路径中,我给它的环境是空的。
我的问题是为什么
答案 0 :(得分:7)
根据The import system - The module cache,
导入搜索期间检查的第一个位置是
sys.modules
。这个 mapping用作以前所有模块的缓存 导入,包括中间路径。所以,如果foo.bar.baz是 以前导入的,sys.modules将包含foo的条目, foo.bar和foo.bar.baz。每个键都有其值 相应的模块对象。导入期间,会在
sys.modules
中查找模块名称以及是否 目前,关联值是满足导入的模块,并且 该过程完成。但是,如果值为None,则a 引发ModuleNotFoundError。如果缺少模块名称,Python 将继续搜索模块。
第二个片段成功导入mymodule
;它被缓存在sys.modules
中,因此不会在其他地方进行搜索。
答案 1 :(得分:3)
这与exec()
无关,并且在运行脚本时以及当Python查找要加载的文件时,对sys.path
上可用的内容有一个简单的误解。
你说:
我正在使用以下程序。重要的是,假设这些程序所在的目录中有
mymodule.py
个文件。[...]
然而,第二个片段没有,即使mymodule也不在其路径中
模块在其路径上。脚本所在的目录将添加到模块搜索路径的开头。见Command line:
<强>
<script>
强>执行脚本中包含的Python代码,该代码必须是文件系统路径(绝对路径或相对路径),指向Python文件,包含
__main__.py
文件的目录或包含__main__.py
的zipfile。文件。[...]
如果脚本名称直接引用Python文件,包含该文件的目录将添加到
sys.path
的开头,该文件将作为__main__
执行模块。
大胆强调我的。
因此,您声明的mymodule.py
位于与您正在运行的脚本相同的目录中,位于路径上。
加载后,模块保持加载。如果import <module>
中没有该名称的模块,sys.modules
将仅查看模块搜索路径。如果您使用exec
或不使用导入,则无关紧要。
来自import
statement documentation:
基本的
import
语句(no from子句)分两步执行:
- 找到一个模块,加载并在必要时初始化
- 在
醇>import
语句出现的范围的本地名称空间中定义一个或多个名称。
如有必要部分是重要的一部分。
此外,来自The import system:
import
语句结合了两个操作;它搜索命名模块,然后将搜索结果绑定到本地范围内的名称。[...]
首次导入模块时,Python会搜索模块,如果找到,它会创建一个模块对象,并对其进行初始化。
导入搜索期间检查的第一个位置是
sys.modules
。此映射用作先前已导入的所有模块的缓存,包括中间路径。因此,如果先前已导入foo.bar.baz
,则sys.modules
将包含foo
,foo.bar
和foo.bar.baz
的条目。每个键的值都是相应的模块对象。在导入期间,会在
sys.modules
中查找模块名称,如果存在,则关联的值是满足导入的模块,并且流程完成。
因此,当您的exec()
代码运行时,第一个import mymodule
已经成功,sys.modules[
mymodule ] exists. The second
导入mymodule`找到该对象,搜索结束。