智伤帝的个人博客

智伤帝

马上订阅 智伤帝的个人博客 RSS 更新: https://blog.l0v0.com/atom.xml

Python - Import 机制

2022年4月15日 09:23

前言

  你是否也会为 reload Python 的模块干到烦恼。
  需要在不同的脚本加上 reload 导入的模块确保可以看到代码的更新。
  Python 是怎么缓存 import 的模块的。

TLDR;

  我后来了解了 Python 的加载机制之后弄了一个函数,只要将我们开发的包命名加上,就可以实现整个开发包 reload 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def module_cleanup(module_name):
"""Cleanup module_name in sys.modules cache.

Args:
module_name (str): Module Name
"""
if module_name in sys.builtin_module_names:
return
packages = [mod for mod in sys.modules if mod.startswith("%s." % module_name)]
for package in packages + [module_name]:
module = sys.modules.get(package)
if module is not None:
del sys.modules[package] # noqa:WPS420

# NOTES(timmyliang): 这个操作等同于对 test_module 下所有的 module 进行 reload
module_cleanup("test_module")

  如果我们的 test_module 下有众多脚本就不需要逐个去添加 reload 了。
  万一不小心把 reload 发布出去了也会稍微降低脚本运行的性能。

Python Import

https://docs.python.org/3/reference/import.html

  上面是 Python 的官方文档讲述 Python的 import 的时候背后的运行机理,也可以切换成中文进行阅读。
  这里我将上面的文章结合自己的实践总结一番。

  Python import 模块可以用关键字 import 或者 importlib.import_module()
备注: 关键字调用无法放到 lambda 函数里面,这也是为什么 Python2 下默认 print 无法放入 lambda 里面, python3 print 不再是关键字可以放入 lambda
  使用 import 关键字其实背后执行的是 __import__() 内置方法。
  import 触发之后会从 sys.modules 查找缓存,找不到就从 sys.path 里面匹配模块 (这个过程也会触发 meta_path 等触发自定义的 import 行为)
  找到匹配的模块就会创建模块 否则 raise ModuleNotFoundError
  生成的模块会放入到 sys.modules 进行缓存。

import 执行操作(不考虑自定义 import 情况)

  1. sys.modules 查找模块缓存
  2. sys.path 匹配脚本 生成模块 放入 sys.modules 缓存

sys.modules

  由于 sys.modules 的缓存机制,Python 下次导入就从已经加载的缓存中获取模块,导致模块用的还是旧的代码逻辑。
  相应的也可以修改 sys.modules 的字典实现骚操作

1
2
3
4
5
import sys
sys.modules['a'] = 1

import a
print(a) # 打印 1

  当然这种骚操作不推荐使用就是了。...

剩余内容已隐藏

查看完整文章以阅读更多