首页 > 编程语言 > 详细

2019python面试题-模块加载顺序

时间:2019-09-06 20:55:56      阅读:87      评论:0      收藏:0      [点我收藏+]

Python 解释器是如何查找包和模块的

Python 执行一个 py 文件,无论执行的方式是用绝对路径还是相对路径,interpreter 都会把文件所在的 directory 加入 sys.path 这个 list 中,并且是索引为 0 的位置。Python 就是在 sys.path 中查找包和模块的。

sys.modules 的作用

载入的模块存放在何处? 答案是 sys.modules。 模块一经载入, Python 会把这个模块加入 sys.modules 中供下次载入使用,这样可以加速模块引入,起到缓存作用。sys.modules 是一个 dict 类型的值。python中的全局module集合sys.modules被称为modules缓存,保证了module的唯一性,每当有import操作都会在该sys.modules查找,如果不存在就会将该module加入到sys.modules中。

解释器查找包:

  • 解释器会默认加载一些 modules,除了sys.builtin_module_names 列出的内置模块之外,还会加载其他一些标准库,都存放在sys.modules字典中。sys.modules 包含了所有加载的模块。 import 语句在实际从磁盘上加载模块之前,会先去检查这个字典!*注:内置模块不是标准库,是指 sys.builtin_module_names输出的字符串元组。解释器启动时确实会加载buit-in module,但是,执行print(sys.builtin_module_names)发现,os并不是built-in module。所以,解释器执行 python 文件时,不仅仅是加载了内置模块的!!!使用sys.modules可以看到实际启动时加载的所有模块。
  • 然后就是搜索 sys.path 路径下的模块了。
import sys

print(sys.builtin_module_names)

运行结果:
(_abc, _ast, _codecs, _collections, _functools, _imp, _io, _locale, _operator, _signal, _sre, _stat, _string, _symtable, _thread, _tracemalloc, _warnings, _weakref, atexit, builtins, errno, faulthandler, gc, itertools, marshal, posix, pwd, sys, time, xxsubtype, zipimport)

 

这样的查找顺序将会导致同名包或模块被遮蔽(如下):

# tree
$ tree . -L 1
.
├── __init__.py
├── name
├── os.py
├── test2.py
├── test.py
└── test.pyc

# test2.py
import os
from redis import Redis
from test import hello

print(Now in test2.py)
print(os.getcwd())

# 执行 python test2.py
$ python test2.py
Traceback (most recent call last):
  File "test2.py", line 2, in <module>
    from redis import Redis
ImportError: No module named redis

 

这里的 os 模块并不是 built-in module的,上面已经将 sys.builtin_module_names 内容打印出来了。只是 Python 解释器启动时就加载到了 sys.modules中缓存起来了。所以,即使在同目录下有同名模块,解释器依然是可以找到正确的 os 模块的(sys.modules中的os模块)!如果你在import os之前,先执行del sys.modules[‘os‘],那么,标准模块 os 就会被同目录下的 os.py 屏蔽了。

*注:del删除模块只是把模块从当前命名空间中删除,但该module依然存在于module缓存中。

redis 属于第三方模块,默认安装位置是 Python 环境变量中的 site-packages,解释器启动之后,会将此目录加到 sys.path,由于当前目录会在 sys.path 的首位,当前目录的 redis 优先被找到了,site-packages 中的 redis 模块被屏蔽了。

 

综上所述,搜索的一个顺序是:sys.modules 缓存 -> sys.path[0] 即当前目录查找 -> sys.path[1:]路径查找。

*注:同时发现,模块被加载的时候,其中非函数或类的语句,例如 print(‘hello‘)name=michael等,是会在 import的时候,默认就执行了。

 

 

2019python面试题-模块加载顺序

原文:https://www.cnblogs.com/yekushi-Z/p/11477985.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!