导入或不导入模块时执行行为之间的区别

Difference between exec behavior when module is imported or not

我是以下节目的 运行。重要的是,假设在这两个程序所在的目录中有 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所在的目录不在path中)。然而,第二个片段没有,即使 mymodule 也不在它的路径中并且我给它的环境是空的。

我的问题是为什么

根据The import system - The module cache,

The first place checked during import search is sys.modules. This mapping serves as a cache of all modules that have been previously imported, including the intermediate paths. So if foo.bar.baz was previously imported, sys.modules will contain entries for foo, foo.bar, and foo.bar.baz. Each key will have as its value the corresponding module object.

During import, the module name is looked up in sys.modules and if present, the associated value is the module satisfying the import, and the process completes. However, if the value is None, then a ModuleNotFoundError is raised. If the module name is missing, Python will continue searching for the module.

第二个片段导入成功mymodule;它缓存在 sys.modules 中,因此不会在其他地方进行搜索。

这与 exec() 无关,只是对 运行 脚本以及 Python 看起来时 sys.path 上可用内容的简单误解用于加载文件。

您说:

I am running to of the following programs. Importantly, imagine that there is mymodule.py file in the directory where both these programs are located.

[...]

The second snippet, however, does not, even though mymodule is also not in its path

模块在其路径上。您的脚本所在的目录被添加到模块搜索路径的开头。见 Command line:

<script>

Execute the Python code contained in script, which must be a filesystem path (absolute or relative) referring to either a Python file, a directory containing a __main__.py file, or a zipfile containing a __main__.py file.

[...]

If the script name refers directly to a Python file, the directory containing that file is added to the start of sys.path, and the file is executed as the __main__ module.

大胆强调我的。

因此,您声明的 mymodule.py 与您的脚本 运行 位于同一目录中,就在路径上。

加载后,模块保持加载。如果 sys.modules 中还没有同名模块,import <module> 只会查看模块搜索路径。使用 exec 或不进行导入都没有关系。

来自import statement documentation:

The basic import statement (no from clause) is executed in two steps:

  1. find a module, loading and initializing it if necessary
  2. define a name or names in the local namespace for the scope where the import statement occurs.

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

此外,来自The import system

The import statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope.

[...]

When a module is first imported, Python searches for the module and if found, it creates a module object, initializing it.

来自The module cache

The first place checked during import search is sys.modules. This mapping serves as a cache of all modules that have been previously imported, including the intermediate paths. So if foo.bar.baz was previously imported, sys.modules will contain entries for foo, foo.bar, and foo.bar.baz. Each key will have as its value the corresponding module object.

During import, the module name is looked up in sys.modules and if present, the associated value is the module satisfying the import, and the process completes.

所以当您的 exec() 代码运行时,第一个 import mymodule 已经成功并且 sys.modules[mymodule] exists. The secondimport mymodule` 找到了那个对象,并且搜索结束。