与 Python 2 不同,reload 在最新的 Python 中不再作为内建函数存在了,而被移入标准库 importlib 模块中。
实验1,reload基本使用
假设我们有个模块叫做config.py
导入一下config模块(如果导入报错找不到config模块,请配置模块的搜索路径先再来测试如下的步骤),如下
我们在右边终端修改b变量的值为20保存退出,再次导入(这个时候我们退出左边的交互式环境),可以看到b的值并没有发生变化,那有没有不退出左边的交互式环境,热加载呢
有的,这个时候reload就派上用场了,可以看到reload实现了在不退出左边交互式环境的情况下实现了重新加载到了config模块中b最新的值
实验二,reload的局限性
通过 reload 函数重新加载模块,Python 将以原模块对象属性空间为全局/局部名字空间,再次执行模块代码。这种行为将导致一些诡异的现象,同时也是我们需要注意的地方,我们来看看。
我们在刚刚config.py的同级目录新建一个test.py
当我们删除test模块中的变量a时,只要a被左边导入过了,那么变量a在左边一直存在,验证如下。
可以看到删除a和没删除a,a变量均存在左边的test模块中正常输出删除变量a之前的值
当我们在test.py中变量进行修改时
如果我们一开始导入变量b到左边是下面这种形式导入的
然后我们对变量b在右边进行修改之后,reload导入查看b的值,结果如下
总结:
- 上面的对比已经很明显了,具体为什么会呈现出对应的结果,请自行去研究关于模块加载以及模块代码执行过程。
- 通过 reload 实现热更新,最好通过模块对象引用模块属性,不要直接导入。
- 如果在模块 test 中 import 其他模块,reload 模块 test 时,其他模块不会 reload 。这是要么显式 reload 其他模块,还要特别注意顺序;要么将其他模块路径从 sys.modules 中剔除,之后 Python 将全新加载它。可以将 sys.modules 理解成模块对象运行时缓存,Python 导入一个模块后,将以模块路径为 key ,以模块对象为 value 保存在该字典中。当同一模块被二次 import 时,Python 直接从这取出已加载的模块对象,避免重复加载。因此,当我们将某个模块从 sys.modules 中剔除,Python 将创建新的模块对象并执行模块代码。