源代碼的編碼問題對於任何語言的源文件都是存在的,只不過對於腳本語言,這個問題更突出一些。
有的人可能會說,既然源代碼在文本編輯器中可以正常顯示,說明編碼沒有問題,編輯器可以識別它,為什么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
這兩個文檔描述了一些實現相關的細節,值得一看。