2019python面试题-模块加载顺序
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
的时候,默认就执行了。
原文地址:https://www.cnblogs.com/yekushi-Z/p/11477985.html
- Linux 系统与数据库安全
- 这或许是对小白最友好的python入门了吧——12,列表深入体验
- 初识SqlLite ---.net连接数据库
- 【实践操作】:六步教你如何用开源框架Tensorflow对象检测API构建一个玩具检测器
- 这或许是对小白最友好的python入门了吧——11,if语句初体验
- 你的网站做好神马搜索优化了吗?神马搜索站长工具提交
- 应用程序的通信成本
- 这或许是对小白最友好的python入门了吧——18,定义函数
- 【深度学习】图片风格转换应用程序:使用CoreML创建Prisma
- 压力测试中存在的问题
- 这或许是对小白最友好的python入门了吧——18,用while循环处理列表
- 如何在js中将统计代码图标隐藏
- 警惕IT黑洞
- 这或许是对小白最友好的python入门了吧——17,while循环
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法