標籤:color string 查看 匯入模組 prefix 語言 協助文檔 for 模組
充電時刻——模組
python的標準安裝包含一組模組,稱為標準庫。
模組
>>> import math
>>> math.sin(0)
0.0
模組是程式
不論什麼python程式都能夠作為模組匯入。
$ cat hello.py
#!/usr/bin/python
print "Hello,signjing!"
$ ./hello.py
Hello,signjing!
如果將python程式儲存在/home/ggz2/magiccube/mysh/pys檔案夾中,運行以下的代碼:
>>> import sys
>>> sys.path.append(‘/home/ggz2/magiccube/mysh/pys‘)
這裡所做的僅僅是告訴解譯器:除了從預設的檔案夾中尋找之外,還須要從檔案夾/home/ggz2/magiccube/mysh/pys中尋找模組。
完畢這個步驟後,就能匯入自己的模組了:
>>> import hello
Hello,signjing!
注意:在匯入模組的時候。可能會看到有新檔案出現,本例中是/home/ggz2/magiccube/mysh/pys/hello.pyc。這個以.pyc為副檔名的檔案是(平台無關的)經過處理(編譯)的,已經轉換成python可以更加有效地處理的檔案。假設稍後匯入同一個模組,python會匯入.pyc檔案而不是.py檔案。除非.py檔案已經改變——在這樣的情況下,會產生新的.pyc檔案。
刪除.pyc檔案不會損害程式(僅僅要等效的.py檔案存在就可以)——必要的時候會建立新的.pyc檔案。
如你所見。在匯入模組的時候。當中的代碼就被運行了。只是再次匯入該模組。就不會發生什麼了。
>>> import hello
>>>
由於匯入模組並不意味著在匯入時運行某些操作。
它們主要用於定義。
此外,由於僅僅須要定義這些東西一次,匯入模組多次和匯入一次的效果是一樣的。
模組用於定義
模組在第一次匯入程式中時被運行。
這看起來有點用——但並不算非常實用。真正的用處在於它們(像類一樣)能夠保持自己的範圍。這就意味著定義的全部類和函數以及賦值後的變數都成為了模組的特性。
在模組中定義函數
$ cat hello2.py
#!/usr/bin/python
def hello():
print "morning,signjing"
>>> import hello2
>>> hello2.hello()
morning,signjing
能夠通過相同的方法來使用不論什麼在模組的全域範圍中定義的名稱。
為了讓代碼可重用,請將它模組化!
在模組中添加測試代碼
模組用來定義函數、類和其它一些內容。但有些時候(其實是常常)。在模組中加入一些檢查模組本身是否正常工作的測試代碼是非常實用的。
$ cat hello3.py
#!/usr/bin/python
def hello():
print "Hello!"
# a test
hello()
>>> import hello3
Hello!
>>> hello3.hello()
Hello!
避免這樣的情況的關鍵在於:“告知”模組本身是作為程式執行還是匯入到其它程式。為了實現這一點。須要使用__name__(雙底線)變數:
>>> __name__
‘__main__‘
>>> hello3.__name__
‘hello3‘
可見。在主程式(包含解譯器的互動式提示符在內)中。變數__name__的值是’__main__’。而在匯入的模組中。這個值被設定為模組的名字。因此。為了讓模組的測試代碼更加好用,能夠將其放置在if語句中:
$ cat hello4.py
#!/usr/bin/python
def hello():
print "hello"
def test():
hello()
if __name__==‘__main__‘:test()
>>> import hello4
>>>
>>> hello4.hello()
hello
讓你的模組可用將模組放置在正確位置
將你的模組放置在正確位置(或者某個正確位置)是非常easy的。僅僅須要找出python解譯器從哪裡尋找模組。然後將自己的檔案放置在那裡就可以。
linux系統:
>>> import sys,pprint
>>> pprint.pprint(sys.path)
[‘‘,
‘/usr/lib64/python26.zip‘,
‘/usr/lib64/python2.6‘,
‘/usr/lib64/python2.6/plat-linux2‘,
‘/usr/lib64/python2.6/lib-tk‘,
‘/usr/lib64/python2.6/lib-old‘,
‘/usr/lib64/python2.6/lib-dynload‘,
‘/usr/lib64/python2.6/site-packages‘,
‘/usr/lib64/python2.6/site-packages/gtk-2.0‘,
‘/usr/lib/python2.6/site-packages‘]
windows系統:
>>> import sys,pprint
>>> pprint.pprint(sys.path)
[‘‘,
‘D:\\software(x86)\\Python27\\Lib\\idlelib‘,
‘C:\\Windows\\system32\\python27.zip‘,
‘D:\\software(x86)\\Python27\\DLLs‘,
‘D:\\software(x86)\\Python27\\lib‘,
‘D:\\software(x86)\\Python27\\lib\\plat-win‘,
‘D:\\software(x86)\\Python27\\lib\\lib-tk‘,
‘D:\\software(x86)\\Python27‘,
‘D:\\software(x86)\\Python27\\lib\\site-packages‘]
每一個字串都提供了一個放置模組的檔案夾。解譯器能夠從這些檔案夾中找到所需的模組。雖然這些檔案夾都能夠使用。但site-packages檔案夾是最佳選擇,由於它就是用來做這些事情的。
在windows作業系統中的D:\\software(x86)\\Python27\\lib\\site-packages下建立檔案another_hello.py:
def hello():
print "hello,Win7"
>>> import another_hello
>>> another_hello.hello()
hello,Win7
可見。僅僅要將模組放入類似site-packages這種檔案夾中,全部程式就都能將其匯入了。
告訴編譯器去哪裡找
“將模組放置在正確的位置”這個解決方式在下面幾種情況下可能並不適用:
1)不希望將自己的模組填滿python解譯器的檔案夾;
2)沒有python解譯器檔案夾中隱藏檔的許可權。
3)想將模組放在其它地方
既然如此,那就告訴解譯器去哪裡找。之前提到了sys.path。但這不是通用的方法。標準的實現方法是在PYTHONPATH環境變數中包括模組所在的檔案夾。
PYTHONPATH環境變數的內容會由於使用的作業系統不同而有所差異,但從基本上來說。它與sys.path非常類似——一個資料夾清單。
環境變數並非python解譯器的一部分。它們是作業系統的一部分。
提示:不須要使用PYTHONPATH來更改sys.path。
路徑設定檔提供了一個實用的捷徑。能夠讓python替你完畢這些工作。路徑設定檔是以.pth為副檔名的檔案,包含應該加入到sys.path中的檔案夾資訊。空行和以#開頭的行都會被忽略。
以import開頭的檔案會被運行。對於Windows來說,使用sys.prefix定義的檔案夾名;在unix和mac OSX中則使用site-packages檔案夾。
命名模組
包括模組代碼的檔案要和模組名一樣——再加上.py副檔名。
在windows系統中,也能夠使用.pyw副檔名。
包
為了組織好模組,能夠將它們分組為包。包基本上就是另外一類別模組。
有趣的地方就是它們都能包括其它模組。
當模組儲存在檔案裡時(副檔名為.py),包就是模組所在的檔案夾。為了讓python將其作為包對待。它必須包括一個命名為__init__py的檔案(模組)。假設將它作為普通模組匯入的話,檔案的內容就是包的內容。比方有個名為constants的包,檔案constants/__init__.py包括語句PI=3.14,那麼能夠這麼做:
import constants
print constants.PI
為了將模組放置在包內。直接把模組放在包檔案夾內就可以。
探究模組
怎樣獨立地探究模組,是極有價值的技能。由於職業生涯中可能會遇到非常多實用的模組。
模組中有什麼
探究模組最直接的方式就是在python解譯器中研究它們。
第一件事就是匯入它。
如果有個叫做copy的標準模組:
>>> import copy
使用dir
查看模組中包括的內容能夠使用dir函數,會將對象(以及模組的全部函數、類、變數等)的全部特性列出。
>>> dir(copy)
[‘Error‘, ‘PyStringMap‘, ‘_EmptyClass‘, ‘__all__‘, ‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘_copy_dispatch‘, ‘_copy_immutable‘, ‘_copy_inst‘, ‘_copy_with_constructor‘, ‘_copy_with_copy_method‘, ‘_deepcopy_atomic‘, ‘_deepcopy_dict‘, ‘_deepcopy_dispatch‘, ‘_deepcopy_inst‘, ‘_deepcopy_list‘, ‘_deepcopy_method‘, ‘_deepcopy_tuple‘, ‘_keep_alive‘, ‘_reconstruct‘, ‘_test‘, ‘copy‘, ‘deepcopy‘, ‘dispatch_table‘, ‘error‘, ‘name‘, ‘t‘, ‘weakref‘]
一些名字下面劃線開始——暗示(約定俗成)它們並非為在模組外部使用而準備的。過濾到它們:
>>> [n for n in dir(copy) if not n.startswith(‘_‘)]
[‘Error‘, ‘PyStringMap‘, ‘copy‘, ‘deepcopy‘, ‘dispatch_table‘, ‘error‘, ‘name‘, ‘t‘, ‘weakref‘]
all變數
__all__這個名字包括一個列表,在copy模組內部被設定。
>>> copy.__all__
[‘Error‘, ‘copy‘, ‘deepcopy‘]
它定義了模組的公用介面。
更準確地說,它告訴解譯器:從模組匯入全部名字代表什麼含義。
使用例如以下代碼from copy import *。則僅僅能使用__all__變數中的函數。要匯入PyStringMap的話,就得顯式地實現,或者匯入copy然後使用copy.PyStringMap,或者使用from copy import PyStringMap。
在編寫模組的時候,像設定__all__這種技術還是相當實用的。
由於模組中可能會有一大堆其它程式不須要或不想要的變數、函數和類,__all__會“客氣地”將它們過濾了出去。
假設沒有設定__all__,用import *語句預設將會輸出模組中全部不下面劃線開頭的全域名稱。
用help擷取協助
對於探究工作。互動式解譯器是個很強大的工具。而對該語言的精通程度決定了對模組探究的程度。只是還有個標準函數可以為你提供日常所需的資訊,這個函數叫做help。
>>> help(copy.copy)
Help on function copy in module copy:
copy(x)
Shallow copy operation on arbitrary Python objects.
See the module‘s __doc__ string for more info.
>>>
其實。上面的協助文檔是從copy函數的文檔字串中提取出的:
>>> print copy.copy.__doc__
Shallow copy operation on arbitrary Python objects.
See the module‘s __doc__ string for more info.
>>>
使用help與直接檢查文檔字串相比。優點在於獲得很多其它資訊。
help(copy)會列印出很多其它資訊,此處略;
文檔
並不是每一個模組或函數都有不錯的文檔字串(雖然都應該有)。有些時候可能須要十分透徹地描寫敘述這些模組和函數是怎樣工作的。
學習python編程最實用的文檔莫過於python庫參考。它對全部標準庫中的模組都有描寫敘述。
使用源碼
對於希望真正理解python語言的人來說。要瞭解模組,是不能脫離源碼的。
閱讀源碼其實是學習python最好的方式——除了自己編寫代碼外。
真正的閱讀不是問題,可是問題在於源碼那裡。假設希望閱讀標準模組copy的源碼。一種方案是檢查sys.path。然後自己找。還有一種是檢查模組的__file__屬性:
>>> copy.__file__
‘D:\\software(x86)\\Python27\\lib\\copy.pyc‘
注意:一些模組並不包括不論什麼能夠閱讀的python源碼。它們可能已經融入到解譯器內了(比方sys模組),或者可能是使用c語言寫成的。
python基礎教程_學習筆記12:充電時刻——模組