导入模块时执行行为的区别

时间:2018-02-27 19:08:51

标签: python exec python-import

我正在使用以下程序。重要的是,假设这些程序所在的目录中有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也不在它的路径中,我给它的环境是空的。

我的问题是为什么

2 个答案:

答案 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子句)分两步执行:

     
      
  1. 找到一个模块,加载并在必要时初始化
  2.   
  3. import语句出现的范围的本地名称空间中定义一个或多个名称。
  4.   

如有必要部分是重要的一部分。

此外,来自The import system

  

import语句结合了两个操作;它搜索命名模块,然后将搜索结果绑定到本地范围内的名称。

     

[...]

     

首次导入模块时,Python会搜索模块,如果找到,它会创建一个模块对象,并对其进行初始化。

The module cache

  

导入搜索期间检查的第一个位置是sys.modules。此映射用作先前已导入的所有模块的缓存,包括中间路径。因此,如果先前已导入foo.bar.baz,则sys.modules将包含foofoo.barfoo.bar.baz的条目。每个键的值都是相应的模块对象。

     

在导入期间,会在sys.modules 中查找模块名称,如果存在,则关联的值是满足导入的模块,并且流程完成

因此,当您的exec()代码运行时,第一个import mymodule已经成功,sys.modules[ mymodule ] exists. The second导入mymodule`找到该对象,搜索结束。