最近要做游戏开发的脚本reload,发现有很多问题需要理解,索性看看python的import reload的原理都给看看吧!
- import说明
import做了三件事情:
1.创建了一个namespace,包含了对应的源代码文件中的所有objects。在该文件中所有fuction和method(关于method和function可参考下面)用到的global表达式都从该namespace中查找对象。
2.执行在新的namespace中的可执行代码
3.创建一个指向该module namespace对象的引用。
因此需要注意,如果module中除了定义variable,function和class之外还执行了一些计算和打印操作的话,这些都会在import时执行,因此,尽量不要有太多耗时的code在module中。
使用import...as xx,xx作为namespace的引用只在当前上下文有效。并且module只会load和excute一次,多次import其实只是重新将namespcae绑定到了xx上。
- from ...import
from与import不同的是,只是将指定namespace的定义好的object,创建了一个在当前namespace的引用。其实这就可以解释为啥reload(amodule)时,那么from a import xx,这些不能更改的问题了。
另外,from xx import * 只能用在module的开头部分,因为python fuction scoping rules,所有fuction在编译成internal bytecode时,所有在funciton body中的symbol必须是确定的。
由于python的引用机制,不能使用类似c/c++的global 参数来传值。
比如
如果foo中打印了a的值,那么打印的是spam中a的值,同时,本文件的a是一个指向42的引用,并不会修改spam中a的值。
- Module Search Path
sys.path中记录了解释器的寻找路径list。list可以包含目录、zip和zgg files。zip和zgg文件通常都是一种将多个modules打包成一个文件,方便使用。
比如可以将foo.py和bar.py打包到xx.zip,然后加入到sys.path中后,直接import foo,bar即可。
比如: import sys
sys.path.append(‘xx.zip)
import foo,bar
并且可以sys.path.append(‘xx.zip/tmp/python‘)实现zip文件子目录的添加。
egg file是zip file的升级,添加了一些metadata而已。
注意到,archive只能import py、pyw、pyc、pyo,shared library和c写的module是不可以通过archive添加的。并且通过archive方式添加的py文件,并不会生成pyc文件,影响效率。
- Module Loading and Compilation
import 的module可以归为如下4中类型:
1. .py files; 2. C/C++ extension,并且编译成了 share library或dlls; 3. 包含多个modules的package; 4. 解释器内嵌的modules
当寻找一个module,如foo时,interpreter按sys.path中的顺序依次寻找其中的每一个路径,其中每个路径中按如下顺序寻找文件:
最后上面都没有找到,才会去检查是否匹配built-in module name。
- reload
这点太坑爹,之前一直说python可以hotfix,其实python自身对这些的支持是很少的,大多数比较成熟的方案都是各位大神们workaround的方法...
原因在于,尽管可以从sys.modules中remove a module,但是module并不会真实从内存中删除,因为程序的其他模块可能import了这个module。另外如果这些module中定义了
class并存在instances,instance保存了这些class object,反过来也会保存module的引用。
另外,已经创建的instance如何通过import和unimport来实现其中内容的更新,更是值得思考的方式。
大致今天花了1个半小时看了这些,明天有空把看到的hotfix的两种实现方法给总结一下。