標籤:
最近要做遊戲開發的指令碼reload,發現有很多問題需要理解,索性看看python的import reload的原理都給看看吧!
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不同的是,只是將指定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的值。
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。
這點太坑爹,之前一直說python可以hotfix,其實python自身對這些的支援是很少的,大多數比較成熟的方案都是各位大神們workaround的方法...
原因在於,儘管可以從sys.modules中remove a module,但是module並不會真實從記憶體中刪除,因為程式的其他模組可能import了這個module。另外如果這些module中定義了
class並存在instances,instance儲存了這些class object,反過來也會儲存module的引用。
另外,已經建立的instance如何通過import和unimport來實現其中內容的更新,更是值得思考的方式。
大致今天花了1個半小時看了這些,明天有空把看到的hotfix的兩種實現方法給總結一下。
python Reload的準備知識