原始碼的編碼問題對於任何語言的源檔案都是存在的,只不過對於指令碼語言,這個問題更突出一些。
有的人可能會說,既然原始碼在文字編輯器中可以正常顯示,說明編碼沒有問題,編輯器可以識別它,為什麼Python還要求聲明原始碼的編碼呢?
這是因為,明確地聲明編碼可以簡化Python解譯器的實現,免得它去猜測源檔案的編碼,這樣既會增加解譯器的複雜性,也會減慢程式的執行速度(畢竟是解釋執行)。況且,程式運行必須是精確的,不能靠猜測。
從Python 2.3開始,可以在Python源檔案中明確地聲明字元編碼,預設是7-bit ASCII編碼。
字元編碼聲明是以在源檔案第一行或者第二行出現的一個魔法注釋來實現的:
# coding=<encoding name>
至於為什麼必須是第一行或者第二行,這個很好解釋:既然要解釋一個檔案,必須在最開始的時候就知道字元編碼,但是在Unix/Linux平台上,第一行可能留給了Python解譯器聲明,#!/usr/bin/python,這也是一個魔法注釋。
如果聲明的編碼Python解譯器不認識,那麼在編譯階段(對於CPython,這就是指將py檔案轉換成pyc檔案)就會報錯。
如果聲明的編碼與實際不符(就是說,檔案實際上是以另外的編碼儲存的),出錯的可能性很大,但是並非一定會出錯,畢竟編碼之間可能有一定的重疊。
如果沒有聲明源檔案的編碼,但是卻使用了7-bit ASCII之外的字元,那麼在編譯(對於CPython,這就是指將py檔案轉換成pyc檔案)的時候會出錯,並且顯示SyntaxError。
非7-bit ASCII字元大部分出現在字串字面常量中,一些人會認為使用unicode字串字面常量會解決編碼的問題,但這完全是另一個層面上的問題,如果源檔案的編碼沒有弄對,根本還到不了討論unicode字串那一步。
對於Windows平台而言,如果源檔案是以utf-8格式儲存的,它會在檔案的開頭加上BOM(Byte Order Mark),對於utf-8,這就是\xef\xbb\xbf,此時,無需對檔案編碼進行聲明,如果要聲明的話,也必須是utf-8,否則編譯出錯。
互動式輸入視窗是有源檔案編碼的,允許輸入中文,顯然不是ascii。
Windows和Unix/Linux的分行符號序列不相同,有的時候這也可能導致問題。
總之,如果編碼有問題,編譯時間就會出錯,如果運行時輸出亂碼,那應該是沒有使用unicode字串或者輸出視窗不支援的緣故。
參考文檔:
http://www.python.org/dev/peps/pep-0263/
http://bugs.python.org/issue526840
這兩個文檔描述了一些實現相關的細節,值得一看。