在本章之前,Python 還沒有顯示出太突出的優(yōu)勢。本章開始,讀者就會越來越感覺到 Python 的強(qiáng)大了。這種強(qiáng)大體現(xiàn)在“模塊自信”上,因?yàn)?Python 不僅有很強(qiáng)大的自有模塊(稱之為標(biāo)準(zhǔn)庫),還有海量的第三方模塊,任何人還都能自己開發(fā)模塊,正是有了這么強(qiáng)大的“模塊自信”,才體現(xiàn)了 Python 的優(yōu)勢所在。并且這種方式也正在不斷被更多其它語言所借鑒。
“模塊自信”的本質(zhì)是:開放。
Python 不是一個封閉的體系,是一個開放系統(tǒng)。開放系統(tǒng)的最大好處就是避免了“熵增”。
熵的概念是由德國物理學(xué)家克勞修斯于 1865 年(這一年李鴻章建立了江南機(jī)械制造總局,美國廢除奴隸制,林肯總統(tǒng)遇刺身亡,美國南北戰(zhàn)爭結(jié)束。)所提出。是一種測量在動力學(xué)方面不能做功的能量總數(shù),也就是當(dāng)總體的熵增加,其做功能力也下降,熵的量度正是能量退化的指標(biāo)。
熵亦被用于計(jì)算一個系統(tǒng)中的失序現(xiàn)象,也就是計(jì)算該系統(tǒng)混亂的程度。
根據(jù)熵的統(tǒng)計(jì)學(xué)定義, 熱力學(xué)第二定律說明一個孤立系統(tǒng)的傾向于增加混亂程度。換句話說就是對于封閉系統(tǒng)而言,會越來越趨向于無序化。反過來,開放系統(tǒng)則能避免無序化。
在本教程的《語句(1)》中,曾經(jīng)介紹了 import 語句,有這樣一個例子:
>>> import math
>>> math.pow(3,2)
9.0
這里的 math 就是一個模塊,用 import 引入這個模塊,然后可以使用模塊里面的函數(shù),比如這個 pow() 函數(shù)。顯然,這里我們是不需要自己動手寫具體函數(shù)的,我們的任務(wù)就是拿過來使用。這就是模塊的好處:拿過來就用,不用自己重寫。
這個標(biāo)題,一語道破了模塊的本質(zhì),它就是一個擴(kuò)展名為 .py
的 Python 程序。我們能夠在應(yīng)該使用它的時候?qū)⑺眠^來,節(jié)省精力,不需要重寫雷同的代碼。
但是,如果我自己寫一個 .py
文件,是不是就能作為模塊 import 過來呢?還不那么簡單。必須得讓 Python 解釋器能夠找到你寫的模塊。比如:在某個目錄中,我寫了這樣一個文件:
#!/usr/bin/env Python
# coding=utf-8
lang = "python"
并把它命名為 pm.py,那么這個文件就可以作為一個模塊被引入。不過由于這個模塊是我自己寫的,Python 解釋器并不知道,我得先告訴它我寫了這樣一個文件。
>>> import sys
>>> sys.path.append("~/Documents/VBS/StartLearningPython/2code/pm.py")
用這種方式就是告訴 Python 解釋器,我寫的那個文件在哪里。在這個告訴方法中,也用了一個模塊 import sys
,不過由于 sys 模塊是 Python 被安裝的時候就有的,所以不用特別告訴,Python 解釋器就知道它在哪里了。
上面那個一長串的地址,是 ubuntu 系統(tǒng)的地址格式,如果讀者使用的 windows 系統(tǒng),請寫你所保存的文件路徑。
>>> import pm
>>> pm.lang
'python'
本來在 pm.py 文件中,有一個變量 lang = "Python"
,這次它作為模塊引入(注意作為模塊引入的時候,不帶擴(kuò)展名),就可以通過模塊名字來訪問變量 pm.py
,當(dāng)然,如果不存在的屬性這么去訪問,肯定是要報(bào)錯的。
>>> pm.xx
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'xx'
請讀者回到 pm.py 文件的存儲目錄,是不是多了一個擴(kuò)展名是 .pyc 的文件?如果不是,你那個可能是外星人用的 Python。
解釋器,英文是:interpreter,港臺翻譯為:直譯器。在 Python 中,它的作用就是將 .py 的文件轉(zhuǎn)化為 .pyc 文件,而 .pyc 文件是由字節(jié)碼(bytecode)構(gòu)成的,然后計(jì)算機(jī)執(zhí)行 .pyc 文件。關(guān)于這方面的詳細(xì)解釋,請參閱維基百科的詞條:直譯器
不少人喜歡將這個世界簡化簡化再簡化。比如人,就分為好人還壞人,比如編程語言就分為解釋型和編譯型,不但如此,還將兩種類型的語言分別貼上運(yùn)行效率高低的標(biāo)簽,解釋型的運(yùn)行速度就慢,編譯型的就快。一般人都把 Python 看成解釋型的,于是就得出它運(yùn)行速度慢的結(jié)論。不少人都因此上當(dāng)受騙了,認(rèn)為 Python 不值得學(xué),或者做不了什么“大事”。這就是將本來復(fù)雜的多樣化的世界非得劃分為“黑白”的結(jié)果。這種喜歡用“非此即彼”的思維方式考慮問題的現(xiàn)象可以說在現(xiàn)在很常見,比如一提到“日本人”,都該殺,這基本上是小孩子的思維方法,可惜在某個過度內(nèi)大行其道。
世界是復(fù)雜的,“敵人的敵人就是朋友”是幼稚的,“一分為二”是機(jī)械的。
就如同剛才看到的那個 .pyc 文件一樣,當(dāng) Python 解釋器讀取了 .py 文件,先將它變成由字節(jié)碼組成的 .pyc 文件,然后這個 .pyc 文件交給一個叫做 Python 虛擬機(jī)的東西去運(yùn)行(那些號稱編譯型的語言也是這個流程,不同的是它們先有一個明顯的編譯過程,編譯好了之后再運(yùn)行)。如果 .py 文件修改了,Python 解釋器會重新編譯,只是這個編譯過程不是完全顯示給你看的。
我這里說的比較籠統(tǒng),要深入了解 Python 程序的執(zhí)行過程,可以閱讀這篇文章:說說 Python 程序的執(zhí)行過程
總之,有了 .pyc 文件后,每次運(yùn)行,就不需要從新讓解釋器來編譯 .py 文件了,除非 .py 文件修改了。這樣,Python 運(yùn)行的就是那個編譯好了的 .pyc 文件。
是否還記得,我們在前面寫有關(guān)程序,然后執(zhí)行,常常要用到 if __name__ == "__main__"
。那時我們寫的 .py 文件是來執(zhí)行的,這時我們同樣寫了 .py 文件,是作為模塊引入的。這就得深入探究一下,同樣是 .py 文件,它是怎么知道是被當(dāng)做程序執(zhí)行還是被當(dāng)做模塊引入?
為了便于比較,將 pm.py 文件進(jìn)行改造,稍微復(fù)雜點(diǎn)。
#!/usr/bin/env Python
# coding=utf-8
def lang():
return "Python"
if __name__ == "__main__":
print lang()
如以前做的那樣,可以用這樣的方式:
$ Python pm.py
python
但是,如果將這個程序作為模塊,導(dǎo)入,會是這樣的:
>>> import sys
>>> sys.path.append("~/Documents/VBS/StarterLearningPython/2code/pm.py")
>>> import pm
>>> pm.lang()
'python'
因?yàn)檫@時候 pm.py 中的函數(shù) lang() 就是一個屬性:
>>> dir(pm)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'lang']
同樣一個 .py 文件,可以把它當(dāng)做程序來執(zhí)行,還可以將它作為模塊引入。
>>> __name__
'__main__'
>>> pm.__name__
'pm'
如果要作為程序執(zhí)行,則__name__ == "__main__"
;如果作為模塊引入,則 pm.__name__ == "pm"
,即變量__name__
的值是模塊名稱。
用這種方式就可以區(qū)分是執(zhí)行程序還是作為模塊引入了。
在一般情況下,如果僅僅是用作模塊引入,可以不寫 if __name__ == "__main__"
。
為了讓我們自己寫的模塊能夠被 Python 解釋器知道,需要用 sys.path.append("~/Documents/VBS/StarterLearningPython/2code/pm.py")
。其實(shí),在 Python 中,所有模塊都被加入到了 sys.path 里面了。用下面的方法可以看到模塊所在位置:
>>> import sys
>>> import pprint
>>> pprint.pprint(sys.path)
['',
'/usr/local/lib/python2.7/dist-packages/autopep8-1.1-py2.7.egg',
'/usr/local/lib/python2.7/dist-packages/pep8-1.5.7-py2.7.egg',
'/usr/lib/python2.7',
'/usr/lib/python2.7/plat-i386-linux-gnu',
'/usr/lib/python2.7/lib-tk',
'/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/usr/local/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages/PILcompat',
'/usr/lib/python2.7/dist-packages/gtk-2.0',
'/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
'~/Documents/VBS/StarterLearningPython/2code/pm.py']
從中也發(fā)現(xiàn)了我們自己寫的那個文件。凡在上面列表所包括位置內(nèi)的 .py 文件都可以作為模塊引入。不妨舉個例子。把前面自己編寫的 pm.py 文件修改為 pmlib.py,然后把它復(fù)制到'/usr/lib/Python2.7/dist-packages
中。(這是以 ubuntu 為例說明,如果是其它操作系統(tǒng),讀者用類似方法也能找到。)
$ sudo cp pm.py /usr/lib/python2.7/dist-packages/pmlib.py
[sudo] password for qw:
$ ls /usr/lib/python2.7/dist-packages/pm*
/usr/lib/Python2.7/dist-packages/pmlib.py
文件放到了指定位置??聪旅娴模?/p>
>>> import pmlib
>>> pmlib.lang
<function lang at 0xb744372c>
>>> pmlib.lang()
'python'
也就是,要將模塊文件放到合適的位置——就是 sys.path 包括位置——就能夠直接用 import 引入了。
將模塊文件放到指定位置是一種不錯的方法。當(dāng)程序員都喜歡自由,能不能放到別處呢?當(dāng)然能,用 sys.path.append()
就是不管把文件放哪里,都可以把其位置告訴 Python 解釋器。但是,這種方法不是很常用。因?yàn)樗灿新闊┑牡胤剑热缭诮换ツJ较?,如果關(guān)閉了,然后再開啟,還得從新告知。
比較常用的告知方法是設(shè)置 PYTHONPATH 環(huán)境變量。
環(huán)境變量,不同操作系統(tǒng)的設(shè)置方法略有差異。讀者可以根據(jù)自己的操作系統(tǒng),到網(wǎng)上搜索設(shè)置方法。
我以 ubuntu 為例,建立一個 Python 的目錄,然后將我自己寫的 .py 文件放到這里,并設(shè)置環(huán)境變量。
:~$ mkdir Python
:~$ cd python
:~/Python$ cp ~/Documents/VBS/StarterLearningPython/2code/pm.py mypm.py
:~/Python$ ls
mypm.py
然后將這個目錄 ~/Python
,也就是 /home/qw/Python
設(shè)置環(huán)境變量。
vim /etc/profile
提醒要用 root 權(quán)限,在打開的文件最后增加 export PATH = /home/qw/python:$PAT
,然后保存退出即可。
注意,我是在 ~/Python
目錄下輸入 Python
,進(jìn)入到交互模式:
:~$ cd Python
:~/python$ Python
>>> import mypm
>>> mypm.lang()
'Python'
如此,就完成了告知過程。
__init__.py
方法__init__.py
是一個空文件,將它放在某個目錄中,就可以將該目錄中的其它 .py 文件作為模塊被引用。這個具體應(yīng)用參見用 tornado 做網(wǎng)站(2)
總目錄 | 上節(jié):錯誤和異常(3) | 下節(jié):標(biāo)準(zhǔn)庫(1)
如果你認(rèn)為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。