本文经验仅供参考。
概要
既不了解 import
原理,也不了解 ModuleSpec, loader, importer
,更不了解 importlib
模块的情况下,所写出的邪门歪道式强行重载主模块(__main__
)的方法。
别名/Alias for SEO
重载 / 重新加载 / 热重载 / 热更新
主模块 / 当前模块 / 顶层模块 / 顶层脚本环境 / 顶层代码 / 顶层文件 / 主文件
权宜之计 / 解决方法 / 怎么 / 怎样 / 如何
交互模式 / 交互式 / 互动式
Python3 / Python 3.x / py3
top-level script, interactive mode, main module reload, workaround, how to
权宜之计/TL;DR
示例:
1 | def reload__main__(): |
或者这篇讨论中列举的方法?(未验证)
常见问题/FAQ
- 方法可靠吗?
不可靠,这是未经任何正式文档记录的旁门左道。
- 适用情况?
适用于
python -i
交互模式下对当前主模块脚本文件(__main__
)整个模块的重载。
但未必适用于其他交互式/REPL情况,例如python -m idlelib -r
IDLE 下用上述方法重载主模块会失败。 - 会影响已加载模块吗?
不会顺便重载其他模块,也不会影响已经加载的旧模块对象。
- 为什么示例代码运行后没有效果?
视乎
Python3
具体版本的不同,方法未必适用。(你环境有问题吧?) - 有什么副作用?
重载当前主模块必然会导致全局命名空间的混乱,因此应当谨慎使用。
- 对任何
Python3
脚本文件都适用吗?单文件模块视乎其文件名未必能进行
import
操作,如含有.
(点分隔符)的情况。 - 如何重载其他模块?
如果只需要重载模块,可以使用
importlib.reload()
,在此不再赘述。 - 其他交互式/REPL情况要如何重载主模块?
不清楚,也许可以尝试获取主模块路径,从路径导入并重载模块再覆盖全局变量的办法。
(不适用的原因也许是因为“主模块”不是真正的“顶层模块(__main__
)”?)(用回python -i
)(ipython %autoreload
黑魔法)
目录
- 概要
- 别名/Alias for SEO
- 权宜之计/TL;DR
- 常见问题/FAQ
- 目录
- 解决过程
- 过程目标
- 具体说明
- 原理
- 具体实现
- 相关
- 参考
解决过程
直接原因:以 python -i
交互模式调试时方便重载。
环境:Win10
过程目标
- 重载当前主模块(
__main__
)近似于
from ... import *
的对应reload()
方式。 - 重载模块名中含有
.
(点分隔符)的模块直接使用
reload()
源码进行邪门歪道式强行重载。(命名不规范,调试两行泪) - (获取当前主模块文件路径)
__file__
sys.argv[0]
sys.modules['__main__'].__dict__['__loader__'].__dict__['path']
具体说明
原理
参考相关文档及源码,在此不赘述:
- https://docs.python.org/zh-cn/3.6/library/importlib.html#importing-a-source-file-directly
- https://github.com/python/cpython/blob/3.6/Lib/importlib/__init__.py
- https://github.com/python/cpython/blob/c352e6c7446c894b13643f538db312092b351789/Lib/importlib/_bootstrap.py#L598
- https://docs.python.org/zh-cn/3.6/faq/programming.html#when-i-edit-an-imported-module-and-reimport-it-the-changes-don-t-show-up-why-does-this-happen
- https://docs.python.org/zh-cn/3.6/library/sys.html#sys.modules
具体实现
关键在于如何获取并重载当前主模块。
除了上文示例所述,具体还有几种实现方法,但可能效果上各自有些差异。(重载有四种写法)
代码全凭印象,未经严格验证,实际效果可能有出入。
1 | import sys, os, importlib |
相关
import
的替代:1
importlib.import_module(mod_name)
1
__import__(mod_name, globals(), locals(), [], 0)
事后找到的相关讨论
(闭门造车轮)(术语不规范,搜索两行泪)顶层模块
__main__
参考
- https://stackoverflow.com/questions/22442546/how-to-reload-after-from-module-import/22442644#22442644
- https://www.python.org/dev/peps/pep-0499/#proposal
- https://stackoverflow.com/questions/1828127/how-to-reference-python-package-when-filename-contains-a-period/1828249#1828249
- https://stackoverflow.com/questions/602846/how-can-i-access-the-current-executing-module-or-class-name-in-python/41233151#41233151
- https://stackoverflow.com/questions/5516783/how-to-reload-python-module-imported-using-from-module-import
- https://docs.python.org/zh-cn/3.6/library/functions.html?highlight=globals#globals
- https://docs.python.org/zh-cn/3.6/library/functions.html?#__import__
- https://www.python.org/dev/peps/pep-3130/
- https://blog.csdn.net/Three_dog/article/details/90298104