在python中清除sys.path之后,导入如何工作?

2024-06-02 04:21:20 发布

您现在位置:Python中文网/ 问答频道 /正文

因此,我正在学习Python模块,根据我的理解,当我们在代码中尝试import一个模块时,Python会查看该模块是否存在于sys.path中,如果不存在,则会引发ModuleNotFoundError

将位置添加到sys.path

因此,假设我想从一个默认情况下不存在于sys.path中的位置导入,我可以简单地将这个新位置附加到sys.path中,并且一切正常,如下面的代码段所示

~/Documents/python-modules/usemymodule.py

import sys
sys.path.append("/home/som/Documents/modules")

import mymodule
mymodule.yell("Hello World")

~/Documents/python-modules/modules/mymodule.py

def yell(txt):
    print(f"{txt.upper()}")

清算sys.path

我的疑问是,当我清除整个sys.path列表时,我应该不能导入任何模块,但令我惊讶的是,我仍然可以导入内置的模块。下面的代码工作正常

import sys
sys.path.clear()

import math
math.ceil(10.2)

我认为python内部可能不使用sys.pathsys.path只是python使用的原始列表的一个浅拷贝,但是添加到sys.path是如何工作的,为什么清除后我只能导入内置模块而不能导入自定义模块

我真的被卡住了,任何帮助都会很好。还有一个类似的问题,但它不能回答我的疑问

enter image description here


Tags: 模块path代码pyimporttxtmodules列表
2条回答

我试图复制您的示例,但出乎意料的是没有得到相同的结果(注意:这里是python3.9)

import sys
sys.path.clear()

import math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'math'

但是,这个有效:

import math
del math

import sys
sys.path.clear()

import math

# but removing the reference in sys.modules will break the import again
del sys.modules['math']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'math'

我的猜测是解释器保留了以前导入中对数学模块的引用,因此不需要在sys.path中搜索它

CPython有一个内置模块列表,如文件PC/config.c中定义的math,如下所示:

struct _inittab _PyImport_Inittab[] = {

    {"_abc", PyInit__abc},
    {"array", PyInit_array},
    {"_ast", PyInit__ast},
    {"audioop", PyInit_audioop},
    {"binascii", PyInit_binascii},
    {"cmath", PyInit_cmath},
    ...
};

因此,当它需要导入内置模块时,它会查看此列表。列表中的每个“PyInit”函数都返回内存中的模块对象

然后将该列表公开为sys.builtin_module_names,该列表在sysmodule.c中初始化。然后,调用importlib._bootstrap._find_spec中的导入代码并遍历sys.meta_path中的导入工厂列表。其中一个是importlib._bootstrap.BuiltinImporter,负责导入内置模块。这表明sys.meta_path

>>> import sys
>>> sys.modules['math']
<module 'math' (built-in)>
>>> sys.path.clear()
>>> import math  # This works because math is in the module cache.
>>> del sys.modules['math']
>>> import math  # This works because of BuiltinImporter in sys.meta_path!
>>> sys.meta_path.clear()
>>> import math  # This still works because math is in the module cache.
>>> del sys.modules['math']
>>> import math  # This fails because we cleared sys.meta_path!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'math'

这是在Python3.7上运行的-在不同的发行版下可能会有所不同

我想补充一点,您的测试没有考虑sys.modules中的模块缓存。用非构建模块来考虑这个例子:

>>> import requests
>>> import sys
>>> sys.path.clear()
>>> import requests  # This works!
>>> del sys.modules['requests']
>>> import requests  # This doesn't.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'requests'

相关问题 更多 >