昨天在某頻道和 thinker 與 ping 大戰 Python 程式碼該如何縮排。老實說這還真是觸動所有 Python 程式員敏感神經的事。幸好,我們三人各執一端,看來是把可能出現的狀況都吵了一遍 (呃,至少吵得差不多了吧)。
因此,我把 Python 縮排上需要注意的地方,以及昨天討論的成果作個整理。當然,從後文你或許看得出來我是如何進行縮排的 (笑),所以描述上若有偏頗的地方全都是我的錯 (畢竟我懶得改編輯器的設定啦)。
很多人知道 Python 在語法上有些限制。最為人所知的就是 Python 沒有 C 語言中的大括號;程式碼的區塊是用縮排分隔的:
def one_function(param): print param
one_function 定義了一個函式,其中的內容必須要進行縮排。
有些人覺得這樣的 Python 限制重重,但事實上,容易維護的程式都具有良好的縮排,而養成縮排的習慣,其實也可以加快程式撰寫的速度 (我們可以很容易地分辨程式中的邏輯區塊,這對編寫速度有幫助)。
如果我們用 notepad.exe 來寫程式,可能會覺得縮排很辛苦;那是當然,因為工具不對,就會覺得縮排是累贅。vim, emacs, jed 或 ulipad 都是常用來編輯 Python 程式的編輯器,而且都非常好用。
縮排的方式
Python 程式碼只規定用縮排分程式區塊,但沒有規定我們要如何縮排。所以,我們可以寫出這樣的程式碼:
print "Hi" def another_hi(): print "another Hi" if True: print "yet another hi" another_hi()
會得到以下的執行結果:
Hi another Hi yet another hi
嘿,但這樣的縮排哪裡好看了?難看得要死!因此,一般來說,我們作縮排的時候會固定縮排的寬度,剛剛的例子要寫為:
print "Hi" def another_hi(): print "another Hi" if True: print "yet another hi" another_hi()
這樣,每一層縮排都用 4 格,結構就一目了然了。
不是空白的空白
在 ASCII 裡有一種字元,它代表 8 個空白字元,那就是跳格 (tab,或作製表) 字元。絕大多數 (我所知) 的文字編輯器都把跳格字元當作 8 個空白來處理,而 Python 既然如此重視縮排,當然 Python compiler 也不例外,同樣遵守此慣例。
但是,這種不是空白的空白帶有混亂 Python 程式的可能!雖然絕大多數的人把跳格字元當作 8 個空白字元來處理,但這是慣例,不是規定。在某些情況下,讓編輯器改變跳格字元的寬度 (我們稱之為 tabstop) 是很有用的。在現實中,也有很多人的 tabstop 不是 8 (常見的有 2 或 4)。
這會造成什麼問題呢?某個人用了跳格鍵 (tabstop=8) 作縮排,但和空白鍵混在一起用,程式碼在他自己來看是:
def funcname(): (^T )print 1 (^T )if True: (^T )(^T )print 2 (^T ) print 3
很好,排得很整齊。但我的 tabstop=4,我看他的程式碼會是這個樣子:
def funcname(): (^T)print 1 (^T)if True: (^T)(^T)print 2 (^T) print 3
結果我沒有注意到這一點,把所有跳格字元都展開成四格空白字元,程式碼就變成:
def funcname(): print 1 if True: print 2 print 3
完蛋,第四行和第五行的縮排不一致了。這會讓 Python 丟出 IndentationError,程式是不能執行的。
怎麼辦?
為了避免跳格字元給我們找麻煩,我們有一些辦法可想:
- 編輯器的 tabstop 不用預設的 8 是邪惡的,我們要杜絕這種狀況。
- 跳格字元是邪惡的,程式裡不可以有跳格字元出現。
- 我愛跳格字元,不過和空白一起混用縮排會出問題,所以縮排的時候只用跳格字元,空白閃邊。
無論我們選擇哪一種作法,基本上都能解決問題。身為一位負責任的程式設計師,在看到別人寫的程式碼時,要注意判斷拿到手上的程式碼是哪一種;若無必要,請依照原來的縮排慣例繼續編寫。
Python 的爸爸給我們的建議
「絕對不要把跳格和空白混在一起。」
這句話是 PEP8 裡說的。PEP8 (Python Enhancement Purposal 編號 8) 的作者之一即為 Python 的爸爸 Guido。所謂的「不要混在一起」是指在縮排的時候不要把跳格和空白混在一起用。
當然,如果全世界的跳格都是 8 個字元,有沒有混其實沒關係,因為這樣的設定和 Python 直譯器是一致的,不會發生錯誤。可惜世界並非如此美好。由於常常會有人把跳格字元設成不是 8 個空白,致生之前所述的問題,所以 PEP8 說絕對不要把跳格和空白混在一起。
Note
不要忘記,我們還可以選擇讓所有人都不要雞婆地把跳格字元設成 8 以外的值。
如果你認為 Python 好,或因為任何其它理由而想要投資時間在 Python 上,PEP8 是一份很值得詳讀的文件。除了縮排之外,它還描述了許多良好的程式編寫習慣 (慣例)。當然我們不必照本宣科 (如其前言所述),但一致的慣例,是提昇程式撰寫效率的神兵利器;多人合作開發的時候尤其如此。
Note
updated at 2007/6/10 00:21
- Previous: 沒有 wget 時的代用品 @2007/06/05
- Next: 對 Python 的新手,我建議的縮排方式 @2007/06/08
Please send trackback to: http://blog.seety.org/everydaywork/2007/6/8/683/trackback/.
其實不是為了縮排而放棄 block mark,而是因為既然是用縮排分區塊,{} 或 begin end 這些 block mark 就變成多餘的了。留也無益,棄不可惜。
至於習不習慣這種編寫風格,私以是就是品味的問題了,因人而異。
為了強制用縮排而放棄 {} or begin .. end 好像有點本末倒置的,倒沒有見過其他 language 會像 python 般,為了空格還是 tab 而大打出手
不明白,真的不明白,有人可以解釋給我聽嗎 ?