天天看點

《UNIX/Linux 系統管理技術手冊(第四版)》——2.5 Python腳本程式設計

本節書摘來自異步社群《unix/linux 系統管理技術手冊(第四版)》一書中的第2章,第2.5節,作者:【美】evi nemeth , garth snyder , trent r.hein , ben whaley著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

unix/linux 系統管理技術手冊(第四版)

随着項目變得越來越大、越來越複雜,面向對象的設計和實作所帶來的好處,也就變得越來越清楚。perl錯過了大概5年時間,沒有提供oo特性,雖然它後來又拼命去追趕,但perl版的面向對象程式設計仍然顯得有點兒牽強。

本節介紹python 2。python 3尚在開發之中,可能在本書沒過時之前就能釋出。但是和perl 6不一樣的是,它看上去更像是一種增量更新。

有着很強oo背景的工程師通常會喜歡python和ruby,這兩種腳本程式設計語言都有一種明顯的oo特質。目前,python似乎正處于采納曲線的下降沿,是以對于系統管理來說,它是一種相當流行的工具。包括opensolaris在内的幾種作業系統,主要利用了python的腳本功能。與此相對照,ruby仍然主要用于web開發,很少用作一般性的腳本程式設計。

guido van rossum發明了python。與perl相比,python的代碼更好寫,也更好讀。python提供了一種易于了解的文法,即使沒開發過這種代碼,也很容易掌握。如果覺得要記住用哪種比較操作符很累人,那麼會喜歡上python整齊劃一的方式。python還提供更多的資料類型,有些系統管理者會發現它們很有用。

如果系統上還沒裝好python,可以看看作業系統提供商或者釋出方給出的軟體包清單。它是一種極其常見的軟體包,應該到處都有。如果沒找到,可以從python.org下載下傳python的源代碼。這個地方也一個集中位置,可以找到其他人開發的附加子產品。

對于python而言,要想獲得比我們在這兒給出的介紹更全面的内容,mark pilgrim的dive into python是一個非常好的起步點。從diveintopython.org可以(免費)閱讀或者下載下傳這份文檔,也可以購買apress出版的印刷版圖書。在2.7節裡可以找到完整的參考文獻。

2.5.1 python快速入門

還像往常一樣,我們先從一個簡單“hello,world!”腳本開始。果不其然,python的“hello, world!”幾乎和perl的一模一樣。

要讓這個腳本可以運作,隻要設定它的可執行位,擴充直接調用python來解釋這個腳本:

這樣的一行程式不能展現出python對傳統的突破,這一突破惡名在外,也就是說,縮行在邏輯上很重要。python不用花括号、方括号,或者begin和end來界定代碼塊。處于同一縮進級别的語句自動構成代碼塊。縮行的風格(空格或者制表符,縮進的深度)則無關緊要。python的代碼分塊最好用例子來展示,是以下面就用一條if-then-else語句來說明:

第三行導入sys子產品,它包含數組argv。then和else子句都有兩行,每一部分都縮進到相同的層次。最後的print語句在if語句之外。和在perl裡的情況一樣,python的print語句也接受任意數量的參數。但和perl不一樣的是,python自動在每對參數之間都插入一個空格,并提供一個換行符。可以在print行的末尾多加一個逗号,消除這個換行符;參數為空則告訴print不要輸出換行符。

在一行末尾的冒号一般是該行引入的一個聯系符,它和随後的一個縮進塊關聯到一起。

python的縮行慣例使得代碼格式上的靈活度更低了,但它也有優點,即不同的人所編寫的代碼看上去都一樣,而且還意味着不需要搞得代碼裡到處都有分号,而這些煩人的分号就隻為了結束語句。

python裡的注釋用一個井号(#)開頭,一直持續到行尾,同bash和perl裡的用法一樣。

在代碼行用反斜線結尾,就可以把長長的代碼行分成多行來寫。這樣做的時候,隻有第一行代碼的縮進才重要。不過,如果願意,可以讓後續的代碼行都縮進。即使沒有出現反斜線,但圓括号、方括号或者花括号不配對的代碼行仍會自動觸發續行,但如果出現這樣的情況,可以在代碼裡包含反斜線,讓代碼的結構更清晰。

有些剪切和粘貼操作會把制表符(tab)轉換為空格,除非知道自己要什麼,否則這會讓人抓狂。黃金法則是,絕對不要混用制表符和空格;縮進要麼用制表符,要麼用空格。許多軟體采用傳統的假設,讓制表符應該等于8個空格的距離,對于代碼的可讀性來說,這确實縮進得太厲害了。大多數python使用者似乎都偏向于采用空格,而且縮進4個字元。

不管決定怎樣處理縮行的問題,大多數編輯器都有若幹選項,要麼隻用空白讓制表符為非法,要麼讓空格和制表符顯示得不一樣,進而幫助使用者搞得清楚。在萬不得已的情況下,還可以用expand指令把制表符轉為空格,或者通過perl -pe指令用一個更容易看到的字元串替換制表符。

2.5.2 對象、字元串、數、清單、字典、元組和檔案

python中所有的資料類型都是對象,比起perl中的資料類型來說,這一點讓它們更強大,也更靈活。

在python裡,清單用方括号而不是圓括号括起來。數組的索引(下标)從0開始,在本章介紹的3種腳本程式設計語言中,這是為數不多的幾種沒有變化的概念之一。

python裡新出現了一種叫做“元組(tuple)”的資料類型,它實質上是不能變的清單。元組比數組更快,對于實際上不應該被修改的資料來說,用元組表示更合适。除了用圓括号而不是方括号做定界符之外,元組的文法和清單的一樣。因為(thing)看上去是一個簡單的代數表達式,是以,對于隻包含一個元素的元組,需要用一個額外的逗号來消除它們的含糊意思:(thing, )。

下面是python中出現的幾種基本變量和資料類型:

這個例子産生的輸出如下:

python中的變量不會從文法上展現出來,也不會做類型聲明,但是它們所指的對象的确有一種支援類型。在大多數情況下,python不會替使用者自動做類型轉換,但是單個函數或者操作符可以做轉換。例如,不顯式地把數值轉換為它的字元串表示形式的話,就不能把一個數和一個字元串(用操作符+)連接配接起來。不過,格式化操作符和語句會強制把所有東西都轉為字元串形式。每個對象都有一個字元串表示。

字元串格式化操作符%很像c或者perl語言裡的sprintf函數,但它可以用在字元串出現的任何地方。它是一個雙目操作符,左邊是字元串,右邊是要插入的數值。如果要插入一個以上的數值,那麼必須用元組來表示這些值。

python字典和perl的哈希一樣;也就是說,它是“鍵/值”對的一個清單。字典常量用花括号括起來,每一對“鍵/值”都用一個冒号分隔。

在使用上,python的字典又非常像數組,差別在于下标(鍵)可以是對象而不隻是整數。

python用對象所關聯的方法把打開的檔案按對象來處理。顧名思義,readline方法讀取一行,是以下面的例子從/etc/passwd檔案讀取并列印兩行内容。

print語句裡最後的逗号消除了換行符,因為每行在從原來的檔案讀入的時候就已經帶一個換行符了。

2.5.3 确認輸入的例子

下面的腳本片段是python版的确認輸入的程式,我們現在已經很熟悉這個例子了。它展示了子例程和指令行參數的用法,還展現了其他兩種python化的特性。

除了導入sys子產品之外,我們還導入了os子產品,進而可以使用os.path.isdir這個例程。注意,對于子產品定義的任何代号來說,import指令不會提供通路它們的捷徑;必須使用從子產品名開始的全名。

例程show_usage的定義裡給退出碼賦予了一個預設值,萬一調用程式沒有顯式地指定這個參數,就用這個預設值退出。既然所有的資料類型都是對象,是以用引用來給函數傳參。

數組sys.argv在第0個位置儲存有該腳本的名字,是以它的長度比實際提供的指令行參數個數正好多1。sys.argv[1:3]這樣的形式表示一個數組段。有意思的是,數組段不包括指定範圍裡最後的那個元素,是以這個數組段隻有sys.argv[1]和sys.argv[2]兩個元素。可以簡單地用sys.argv[1:]把從第二個開始的所有元素都包括進來。

同bash和perl一樣,python也有專門的一種“else if”條件;其關鍵字是elif。python也沒有case或者switch語句。

給soure和dest變量的平行指派與perl有點兒不一樣,因為這兩個變量本身不在一個清單裡。兩種形式的平行指派在python裡都可以。

python給數值和字元串的比較運算符都一樣。“不相等”的比較運算符是!=,但卻沒有!這樣的單目運算符;這樣的單目運算符是not。也要搞清楚布爾運算符and和or。

2.5.4 循環

下面的代碼片段用一個for…in結構從1循環到10。

和前面例子裡的數組段一樣,這個範圍的右端點實際上沒有包括進來。輸出值隻有1到9。

1 2 3 4 5 6 7 8 9

這是python裡唯一的for循環類型,但它功能很強大。python的for語句有幾項特性,有别于其他語言。

數值範圍沒有什麼特殊之處。任何對象都可以支援python的循環模型,而且最常見的對象都支援。可以通過一個字元串(按逐個字元)、一個清單、一個檔案(按逐個字元、逐行或者逐塊),以及一個數組段等。

循環可以産生多個值,循環變量也可以有多個。在每次循環的開頭進行的指派,就和python正常的多重指派一樣。

for和while循環都可以在末尾加上else子句。隻有當循環正常終止之後,才執行這個else子句,這和通過一條break語句退出正好相反。這一功能乍看起來似乎與直覺相反,但它能很好地處理某些用例。

下面的腳本示例接受指令行上的一個正規表達式,把它同一個清單進行比對,清單裡是白雪公主中七個小矮人的名字及其衣服的顔色。該腳本列印第一個比對的結果,而且比對正規表達式的部分兩邊用下劃線區分出來。

下面是一些輸出的例子:

給suits指派的語句,展示了python用于字典常量的編碼方式。suits.items()方法是“鍵/值”對的疊代器——每次循環都提取一個小矮人的名字和一種衣服顔色。如果隻想通過鍵做循環,隻需要把代碼寫為for dwarf in suits。

python通過它的re子產品實作對正規表達式的處理。python語言本身沒有任何有關正規表達式的功能,是以用python處理正規表達式比用perl要稍微麻煩一點兒。在本例中,正規表達式的pattern一開始由compile方法,用圓括号括起來第一個指令行參數進行編譯,形成了一個捕獲組。接着,用正規表達式對象的search和sub方法測試和修改字元串。還可以像函數那樣直接調用re.search等方法,把正規表達式當做第一個參數來用。替換字元串裡的1是反過去引用第一個捕獲組的内容。