python 模組的載入
不管是用import還是用from mmmm import *的方式匯入模組,當程式執行之後,回頭在看那個儲存著mmmm.py檔案的目錄中,多了一個檔案:
$ ls mmm*
mmmm.py mmmm.pyc
在這個目錄下面,除了原來的那個mmmm.py之外,又多了一個mmmm.pyc檔案,這個檔案不是我寫的,需要用import的過程說起。
import的工作流程
import mmmm,並不是僅僅將mmmm.py這個檔案裝載到當前位置(檔案內),其實是首先進行了一次運算。當mmmm.py被第一次匯入的時候,python首先要對其進行編譯,生成副檔名為.pyc的同名檔案,然後才執行mmmm模組的程式碼,建立相應的物件等。就如同把大象裝進冰箱,有三步要執行:
- 搜尋。就是python要能夠找到import的模組。怎麼找到,後面講述。
- 編譯。找到模組檔案之後,將其編譯成位元組碼,就是那個.pyc檔案裡面的(關於位元組碼,下面會介紹,請繼續閱讀)。注意,不是什麼時候都編譯的,只有第一次執行時候才編譯,如果mmmm.py檔案改變了,相當於又一個新檔案,也會從新編譯。其實就是.pyc檔案中有一個時間戳,python會自動檢查這個時間戳,如果它比同名的.py檔案時間戳舊,就會從新編譯。否則跳過。當然,如果根本就沒有找到同名的.py原始檔,只有位元組碼檔案.pyc,那麼就只能執行這個了。
- 執行。執行就是前面已經編譯的模組位元組碼檔案,順理成章要執行了。
搜尋模組
一般情況下,python會自動的完成模組搜尋過程。但是,在某些情況下,或許會要求程式設計師來設定搜尋路徑。當import一個模組後,python會按照下面的順序來找那個將要匯入的模組檔案
- 程式的主目錄。上一講中,在codes這個目錄中執行互動模式,這時候的主目錄就是codes,當在那個互動模式中執行import mmmm的時候,就首先在codes這個目錄中搜索相應的檔案(找到.py之後編譯成為.pyc)。當然,後面在網頁程式設計中,所謂主目錄是可以通過頂層檔案設定的目錄。
- PYTHONPATH目錄。這是一個環境變數設定,如果沒有設定則濾去。如何進行環境變數設定,請google啦。
- 標準庫目錄。已經隨著Python的安裝進入到計算機中的那個。
- 任何.pth檔案的內容。如果有這類檔案,最後要在這類檔案中搜索一下。這是一個簡單的方法,在.pth檔案中,加入有效目錄,使之成為搜尋路徑。下圖就是我的計算機上,存放.pth檔案的位置以及裡面放著的.pth檔案
也可以自己編寫.pth檔案,裡面是有關搜尋目錄,儲存到這裡。比如,開啟目錄中的easy-install.pth檔案,發現的內容:
搜尋就是這麼一個過程。這裡建議瞭解即可,不一定非要進行什麼設定,在很多情況下,python都是會自動完成的。特別是初學者,暫且不要輕舉妄動。
過載模組
以mmmm模組為例。
在一個shell裡面,運行了python,並且做了如下操作:
>>> import mmmm
>>> mmmm.web
'https://hiekay.github.io'
下面我再開啟一個shell,編輯mmmm.py這個檔案,對web值進行適當修改:
#!/usr/bin/env python
#coding:utf-8
web = "https://hiekay.github.io, I am writing a python book on line. "
def my_name(name):
print name
class pythoner:
def __init__(self,lang):
self.lang = lang
def programmer(self):
print "python programmer language is: ",self.lang
儲存之後,切換到原來的那個匯入了模組的互動模式:
>>> mmmm.web
'https://hiekay.github.io'
輸出的跟前面的一樣,沒有任何變化,這是為什麼呢?
原來,當匯入模組的時候,只會在第一次匯入時載入和執行模組程式碼,之後就不會重新載入或重新執行了,如果模組程式碼修改了,但是這裡執行的還是修改之前的。
怎麼實現程式碼修改之後,執行新的呢?一種方式就是退出原來的互動模式,再重新進入,再import mmmm。這種方法有點麻煩。Python提供了另外一個函式——reload函式,能夠實現模組的重新載入(簡稱過載),過載後模組程式碼重新執行。如下繼續:
>>> reload(mmmm)
<module 'mmmm' from 'mmmm.py'>
>>> mmmm.web
'https://hiekay.github.io, I am writing a python book on line. '
這下就顯示修改之後的內容了。
特別提醒注意:
- reload是內建函式
- reload(module),module是一個已經存在的模組,不是變數名。