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