在python中清除sys.path之后,导入如何工作?
因此,我正在学习Python模块,根据我的理解,当我们尝试导入代码中的模块时,Python会查看该模块是否存在于sys.path中,如果不存在,则会引发在python中清除sys.path之后,导入如何工作?,python,python-3.x,Python,Python 3.x,因此,我正在学习Python模块,根据我的理解,当我们尝试导入代码中的模块时,Python会查看该模块是否存在于sys.path中,如果不存在,则会引发ModuleNotFoundError 将位置添加到系统路径 因此,假设我想从一个默认情况下不存在于sys.path中的位置导入,我可以简单地将这个新位置附加到sys.path中,一切正常,如下面的代码片段所示 ~/Documents/python modules/usemymodule.py ~/Documents/python模块/modul
ModuleNotFoundError
将位置添加到系统路径
因此,假设我想从一个默认情况下不存在于sys.path
中的位置导入,我可以简单地将这个新位置附加到sys.path
中,一切正常,如下面的代码片段所示
~/Documents/python modules/usemymodule.py
~/Documents/python模块/modules/mymodule.py
清除sys.path
我的疑问是,当我清除整个sys.path
列表时,我应该无法导入任何模块,但出乎意料的是,我仍然可以导入内置的模块。下面的代码工作正常
import sys
sys.path.clear()
import math
math.ceil(10.2)
我认为python内部可能不使用sys.path
,sys.path
只是python使用的原始列表的一个简单副本,但是添加到sys.path
如何工作,为什么清除后我只能导入内置模块而不能导入自定义模块
我真的被卡住了,任何帮助都会很好。还有一个类似的问题,但它不能回答我的疑问
CPython有一个内置模块列表,如文件中定义的math,如下所示:
struct\u inittab\u PyImport\u inittab[]={
{u abc,PyInit_abc},
{“数组”,PyInit_数组},
{u ast,PyInit{u ast},
{“audioop”,PyInit_audioop},
{“binascii”,PyInit_binascii},
{“cmath”,PyInit_cmath},
...
};
因此,当它需要导入内置模块时,它会查看此列表。列表中的每个“PyInit”函数都返回内存中的模块对象
然后,此列表显示为系统内置模块名称,在中初始化。然后,调用importlib.\u bootstrap.\u find\u spec
中的导入代码,并查看sys.meta\u path
中的导入工厂列表。其中一个是importlib.\u bootstrap.BuiltinImporter,它负责导入内置模块。这演示了sys.meta\u路径
:
导入系统
>>>sys.modules['math']
>>>sys.path.clear()
>>>导入数学#这是因为数学在模块缓存中。
>>>del sys.modules['math']
>>>导入数学#由于sys.meta#u路径中的内置端口,这项工作正常!
>>>sys.meta_path.clear()
>>>导入数学#这仍然有效,因为数学在模块缓存中。
>>>del sys.modules['math']
>>>导入数学#此操作失败,因为我们清除了sys.meta_路径!
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ModuleNotFoundError:没有名为“math”的模块
这是在蟒蛇3.7上运行的-在不同的发行版下可能会有所不同
我想补充一点,您的测试没有考虑sys.modules
中的模块缓存。用非构建模块来考虑这个例子:
导入请求
>>>导入系统
>>>sys.path.clear()
>>>导入请求#这很有效!
>>>删除系统模块['requests']
>>>导入请求#这不是。
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ModuleNotFoundError:没有名为“requests”的模块
我试图重现您的示例,但出乎意料的是没有得到相同的结果(注意:这里是python3.9) 导入系统 sys.path.clear() 输入数学 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 ModuleNotFoundError:没有名为“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.clear()
输入数学
#但是删除sys.modules中的引用将再次中断导入
del sys.modules['math']
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ModuleNotFoundError:没有名为“math”的模块
我的猜测是,解释器保留了以前导入时对数学模块的引用,因此不需要在
sys.path
中搜索它。如果内置的东西以某种方式内置在python解释器中,那不是很好吗?所以不需要真正的源文件?不确定是否会是这样。。。但我的猜测是看看python解释器本身所在的位置。看@PatrickArtner我真的不明白你的意思。你是在告诉我在清除之前,看看math.py
在哪里,如果是这样的话,那么它位于/usr/lib/python3.8
,在sys.path
中有一个条目。我最好的猜测是python在二进制文件中内置了一个位置,例如/usr/lib/python$python\u VERSION
,当sys.path
为空时,将其用作回退。这是否回答了您的问题@python_用户不,绝对不是!可以因此,如果我清楚地理解您的意思,如果我在清除sys.path
后尝试导入请求,它将引发ModuleNotFoundError。是的,但前提是您也先将其从缓存中删除。这很奇怪,因为我只是在没有清除缓存的情况下尝试导入请求,它仍然会引发异常。我所做的就是:importsys;sys.path.clear();导入请求
请注意,PC/config.c
是为Windows版本定义该列表的地方。在其他平台上,列表位于从生成的config.c
中。@SomShekharMukherjee我更新了我的答案,提供了有关sys.meta_path
的详细信息。在Python 3.9.5上尝试了这一点,它适用于MeInterest——我和Python聊天中的一些人得到了相互矛盾的结果,即使我们有相同的版本。也许这是操作系统的问题。
import sys
sys.path.clear()
import math
math.ceil(10.2)
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'