標籤:python 模組
參考:
https://www.cnblogs.com/bobo0609/p/6938012.html
https://docs.python.org/2/tutorial/modules.html
1.簡介:
在Python中,一個.py或者.pyc檔案就稱之為一個模組(Module)。即一個檔案被看作一個獨立的模組,一個模組也可以被看做是一個檔案
.py:存放的是python源碼
.pyc:存放的是python解譯器對源碼編譯後的位元組碼
python把檔案名稱去掉.py/.pyc尾碼作為模組名,比如 os.py ,那麼它的模組名就是 os
那麼假設我們當前路徑有個os.py,python怎麼知道它的位置,並匯入使用呢?
這裡就涉及到python的模組搜尋路徑,它的搜尋次序如下:
<1>當前路徑
<2>PYTHONPATH變數自訂的路徑(PYTHONPATH是系統自訂的環境變數,類似centos中的PATH)
<3>安裝python時所定義的路徑
有人會疑惑,python怎麼知道我當前的路徑在哪?
這是因為,python的程式包括一個頂層程式檔案和其它的模組檔案,這個頂層檔案相當於程式執行的入口,類似shell指令碼,我們執行指令碼時必須寫明絕對路勁或者切到對應路徑去執行(這個時候路徑就傳遞了),python也是同理
例子:
[[email protected] python_learn]# pwd/root/python_learn[[email protected] python_learn]# cat getvalue.py#!/usr/local/anaconda2/bin/pythonx='Gx'y='Gy'z='Gz'def f1(x,y,z): x='Ex' z='Ez' print x,y,z def f2(x,y,z):x='Lx'print x,y,z f2(x,y,z)f1(x,y,z)[[email protected] python_learn]# cat index.py import getvalueprint x[[email protected] python_learn]# python index.py Ex Gy EzLx Gy EzTraceback (most recent call last): File "index.py", line 2, in <module> print xNameError: name 'x' is not defined
這裡index.py作為程式入口匯入了getvalue這個模組,顯然,這裡python找到了getvalue模組,因為程式執行到了print x,但是為什麼會有"Ex Gy Ez"這些輸出呢?
這是因為:python在首次匯入模組(import 或者reload)的時候,會立即執行模組檔案的頂層程式碼(不在函數內的代碼,比如變數x'=Gx',函數定義def f1等,只要頂格寫都會被執行),而位於函數主體內的代碼直到函數被調用後才會執行,所以f1(x,y,z)函數被調用了,列印出了"Ex Gy Ez",而f1又自己調用了f2,所以f2函數列印了"Lx Gy Ez"
那麼,既然模組有匯入成功,x變數應該有定義,為何又提示“name 'x' is not defined”呢?
這是因為:為了避免大家的相同編程習慣導致各種變數覆蓋(比如張三和李四被指派寫兩個不同的模組,張三習慣在他的變數中使用x,李四也習慣這樣,那麼當兩個模組都被匯入時,因為變數名相同,必然有一個的值會被覆蓋掉),於是python在匯入模組時,以模組名建立一個新的名稱空間,在新的名稱空間中建立變數。 簡單地說,當匯入getvalue模組的x變數的時候,此時x不再被當成x,而是被當成getvalue.x
例子:(接上例)
[[email protected] python_learn]# cat index.py import getvalueprint getvalue.x[[email protected] python_learn]# python index.py Ex Gy EzLx Gy EzGx
可以看見,此時的print 語句已經可以正常輸出。
那麼,如果我想隨時隨地可以匯入getvalue模組,而又不想切到指定路徑去,那麼該怎麼辦呢?
這個時候,就要用到sys.path這個變數了
例子:
In [2]: import sysIn [3]: sys.pathOut[3]: ['', '/usr/local/anaconda2/bin', '/usr/local/anaconda2/lib/python27.zip', '/usr/local/anaconda2/lib/python2.7', '/usr/local/anaconda2/lib/python2.7/plat-linux2', '/usr/local/anaconda2/lib/python2.7/lib-tk', '/usr/local/anaconda2/lib/python2.7/lib-old', '/usr/local/anaconda2/lib/python2.7/lib-dynload', '/usr/local/anaconda2/lib/python2.7/site-packages', '/usr/local/anaconda2/lib/python2.7/site-packages/IPython/extensions', '/root/.ipython']In [4]: sys.path.insert('/root/python_learn/')---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-4-b628fd39dcd4> in <module>()----> 1 sys.path.insert('/root/python_learn/')TypeError: insert() takes exactly 2 arguments (1 given)In [5]: help (list.insert)In [6]: sys.path.insert(,'/root/python_learn/') File "<ipython-input-6-c98c91c9451b>", line 1 sys.path.insert(,'/root/python_learn/') ^SyntaxError: invalid syntaxIn [7]: sys.path.insert(0,'/root/python_learn/')In [8]: sys.pathOut[8]: ['/root/python_learn/', '', '/usr/local/anaconda2/bin', '/usr/local/anaconda2/lib/python27.zip', '/usr/local/anaconda2/lib/python2.7', '/usr/local/anaconda2/lib/python2.7/plat-linux2', '/usr/local/anaconda2/lib/python2.7/lib-tk', '/usr/local/anaconda2/lib/python2.7/lib-old', '/usr/local/anaconda2/lib/python2.7/lib-dynload', '/usr/local/anaconda2/lib/python2.7/site-packages', '/usr/local/anaconda2/lib/python2.7/site-packages/IPython/extensions', '/root/.ipython']In [9]: import getvalueEx Gy EzLx Gy EzIn [10]: getvalue.xOut[10]: 'Gx'
python按照sys.path的順序來尋找模組,需要注意的是,insert方法需要兩個參數,第一個是索引,這裡使用0,放在第一位,優先尋找我們自己的目錄
如果我們再次import,python並不會再次執行頂層程式碼,而是簡單地重載下記憶體中的對象
例子:
In [29]: import getvalueIn [30]: getvalue reload File "<ipython-input-30-7cba10969034>", line 1 getvalue reload ^SyntaxError: invalid syntaxIn [31]: help(reload)In [32]: reload(getvalue)Ex Gy EzLx Gy EzOut[32]: <module 'getvalue' from '/root/python_learn/getvalue.pyc'>
現在,模組載入沒什麼問題了,但是我覺得每次都要敲完整模組名getvalue,太煩人了,有沒有什麼辦法呢?
這個時候就要用到import-as語句了
例子:
In [33]: import getvalue as gIn [34]: g.xOut[34]: 'Gx'
import xx as x:把本來先建立名稱空間名為getvlaue改成了g,所以調用就簡單了,因為是修改所以此時getvalue這個名稱空間是不存在的,所以不能用getvalue+'.'擷取值
那麼如果我比較任性,就想覆蓋當前環境中的變數x呢?
這個時候就得用到from-import 語句了
例子:
In [35]: from getvalue import xIn [36]: xOut[36]: 'Gx'
from-import語句只會載入對應的屬性或者方法到當前的名稱空間,所以其他語句不會執行
所以python匯入模組,大概分成以下幾類:
import:直接匯入
import Module as Module_alias:給變數取別名
from Module import Attribute/Method: 匯入部分屬性/方法
reload(Module):重新匯入
既然作為模組,就該有作為模組的覺悟,一匯入就瞎執行是會被clear的-_-!!
所以我們不該讓模組中包含不該執行的語句,比如函數不該被調用。但是我又想這個模組檔案有時作為程式頂層檔案執行,有時作為模組被匯入,那麼有辦法嗎?
這個時候就可以用到內建屬性__name__了
例子:
[[email protected] python_learn]# cp getvalue.py New.py[[email protected] python_learn]# vi New.py [[email protected] python_learn]# cat New.py #!/usr/local/anaconda2/bin/pythonx='Gx'y='Gy'z='Gz'def f1(x,y,z): x='Ex' z='Ez' print x,y,z def f2(x,y,z):x='Lx'print x,y,z f2(x,y,z)if __name__ == "__main__" : f1(x,y,z)[[email protected] python_learn]# python New.py Ex Gy EzLx Gy Ez============================================In [6]: import NewIn [7]: New.xOut[7]: 'Gx'In [8]: reload(New)Out[8]: <module 'New' from 'New.pyc'>In [9]: New.__name__Out[9]: 'New'
這裡的內建變數__name__,如果程式是頂層檔案則為"__main__",否則為模組名
2.import的工作機制(摘抄自:https://www.cnblogs.com/bobo0609/p/6938012.html)
import語句匯入指定的模組時會執行3個步驟
1. 找到模組檔案:在模組搜尋路徑下搜尋模組檔案
程式的主目錄
PYTHONPATH目錄
標準連結庫目錄
2.編譯成位元組碼:檔案匯入時會編譯,因此,頂層檔案的.pyc位元組碼檔案在內部使用後會被丟棄,只有被匯入的檔案才會留下.pyc檔案
3.執行模組的代碼來建立其所定義的對象:模組檔案中的所有語句從頭至尾依次執行,而此步驟中任何對變數名的賦值運算,都會產生所得到的模組檔案的屬性
注意:模組只在第一次匯入時才會執行如上步驟,後續的匯入操作只不過是提取記憶體中已載入的模組對象,reload()可用於重新載入模組
包: 用於將一組模組歸併到一個目錄中,此目錄即為包,目錄名即為包名
包是一個有層次的檔案目錄結構,它定義了一個由模組和子包組成的Python應用執行環境
基於包,Python在執行模組匯入時可以指定模組的匯入路徑 import pack1.pack2.mod1
每個包內都必須有__init__.py檔案, __init__.py 可包含python代碼,但通常為空白,僅用於扮演包初始化、替目錄產生模組命名空間以及使用目錄匯入時實現from*行為的角色
python的模組