2016年1月3日 星期日

python import

import是python用來將其他modules匯入目前modules的功能。

我們想要import進來的東西應該可以分為兩種
ㄧ)獨立的module,其路徑應該長得像
/path/m1.py
二)包在package裡面的module,其路徑應該長得像
/path/pkg_path/m2.py
在第二種case中,pkg_path之所以可以顯得和一般的path不同,是因為我們在資料夾下手動加入了一個檔案
/path/pkg_path/__init__.py
有了這個檔案,python就會知道這個資料夾下是放了屬於同一個package的module。這個檔案是可以沒有內容的。
    接下來,不管是哪種case,假如我們想要每次打開python都可以直接import,都應該要將他的路徑加到環境變數中[1]:
export PYTHONPATH="/path:$PYTHONPATH"
注意這裡第二種case"不應該"使用
export PYTHONPATH="/path/pkg_path:$PYTHONPATH"
因為pkg_path整個資料夾算一個單位,若使用後面這種方式import,會使得python可以獨立找到其中的module,也就是下面這種用法會被允許:
m2.func()
,但較正確的用法應該是
pkg_path.m2.func()
也就是說,可以使這些module有pkg_path這個命名空間。
    當我們設定好環境變數,我們可以進入python,看他是不是真的會將PYTHONPATH底下的路徑加入搜尋路徑:
import sys
sys.path

接下來就是import我們的module了,使用
import m1
就可以使用m1裡的功能了
m1.func()
直接執行
m1
就能發現他確實將m1變數連接到m1.pyc這個編譯好的檔案。
    由於我們在pkg_path中有加入__init__.py,因此我們可以執行
import pkg_path
若執行
pkg_path
可以發現變數連接到的就是__init__.pyc。但目前只有將pkg_path這個命名空間加入,還沒有真正將module匯入。執行
import pkg_path.m2
會幫我們加入pkg_path這個命名空間,以及pkg_path.m2這個module。此時才能夠使用
pkg_path.m2.func()

接下來是from ... import ... [3]
我們可以使用
from namespace import module (等同import namespace.module)
from namespace.module import mem
from module import mem
但不能使用
from namespace import module.mem
簡單來說就是要from目前python可以找到的路徑開始,然後import後面的東西,不論是namespace、module(module其實也是一種namespace)或mem。但是mem都要等到他所屬的module存在sys.modules中,才能被使用,只有module以上的namespace被加入是不能使用mem的。

from m1 import func1
from pkg_path.m2 import func1, func2, func3
上面程式具體行為其實類似
func1 = m1.func1
func1 = pkg_path.m2.func1
...
(python中也可以使用變數指向一個function)
也就是說,其實我們是在自己這個module裡面新增一個變數指向import後面的東西,from後面的東西並沒有特別用一個變數去指它。而python會將import時所經過的所有module(namespace)都加入sys.modules。我們之所以在import之後就可以直接使用import後面的東西,是因為新增了一個local變數存這個東西(module、function等),而將module匯入其實是另一件事了,因為即使目前sys.modules中確實是有這個module存在,但若這個指向他的變數不見了,我們依然無法使用這個module。
    因此回去看上面的程式其實會發現有個問題,就是func1被assign了兩次,因此我們最後其實只能使用到pkg_path.m2.func1。這也是為什麼我們不推薦使用
from ... import *
也就是import namespace下所有的東西進來。這樣做可能會造成衝突,因為很有可能有東西的名稱是重複的。
    但如果我們要import的東西名稱真的是重複的,我們可以使用
import name1 as name2
這樣import進來時所新增的變數名稱就能變成name2。最後,這個用法是可以和上面混合的:
from ... import ... as ...

新增:
from .module import ...
這個用法中,.module的那個點代表的是目前的module[8]。比如說,在一個package中可能有很多.py檔,.module就是代表同一個package中的其他module。

其他:
global():列出module namespace。(Note. 在command line(prompt)中直接import的都算global)
local():列出目current namespace。[4]

其他學習:[5][6][7]

參考:
[1] http://stackoverflow.com/questions/3144089/expand-python-search-path-to-other-source
[2] http://stackoverflow.com/questions/448271/what-is-init-py-for
[3] http://stackoverflow.com/questions/9439480/from-import-vs-import
[4] http://stackoverflow.com/questions/7969949/whats-the-difference-between-globals-locals-and-vars
[5] http://openhome.cc/Gossip/Python/ModuleABC.html
[6] http://openhome.cc/Gossip/Python/ImportModule.html
[7] http://openhome.cc/Gossip/Python/ImportImportAsFrom.html
[8] http://stackoverflow.com/questions/7279810/what-does-a-in-an-import-statement-in-python-mean

沒有留言:

張貼留言