昨天在某頻道和 thinkerping 大戰 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,程式是不能執行的。

怎麼辦?

為了避免跳格字元給我們找麻煩,我們有一些辦法可想:

  1. 編輯器的 tabstop 不用預設的 8 是邪惡的,我們要杜絕這種狀況。
  2. 跳格字元是邪惡的,程式裡不可以有跳格字元出現。
  3. 我愛跳格字元,不過和空白一起混用縮排會出問題,所以縮排的時候只用跳格字元,空白閃邊。

無論我們選擇哪一種作法,基本上都能解決問題。身為一位負責任的程式設計師,在看到別人寫的程式碼時,要注意判斷拿到手上的程式碼是哪一種;若無必要,請依照原來的縮排慣例繼續編寫。

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

Posted by yungyuc at 17:47, 2 comments, 0 trackback.
Navigate
Add a trackback
Comments
Re: Python 的縮排 (注意事項)
作為 RubyonRails 的 programmer 的我,覺得 python 不用 C 語言中的大括號,或 ruby 中的 begin .. end 的語法是不可思義的事

為了強制用縮排而放棄 {} or begin .. end 好像有點本末倒置的,倒沒有見過其他 language 會像 python 般,為了空格還是 tab 而大打出手

不明白,真的不明白,有人可以解釋給我聽嗎 ?
moming2k at 2007-08-11 04:15.
Re: Python 的縮排 (注意事項)
來寫上幾萬行就明白了,試試看吧 ;)

其實不是為了縮排而放棄 block mark,而是因為既然是用縮排分區塊,{} 或 begin end 這些 block mark 就變成多餘的了。留也無益,棄不可惜。

至於習不習慣這種編寫風格,私以是就是品味的問題了,因人而異。
yungyuc at 2007-08-11 08:16.
Add a comment

Your name. (required)

Your personal website. (optional)

Your email address. Will not show in page. (suggested, but optional)

Text format is "Plain Text".

Enter "mcbwa"
© hover year to navigate month: powered by django