也來談談python編碼

一、coding:utf-8

讓我們先來看一個示例,源碼文件是utf-8格式:

print('你好 python')

當使用python2執行該程式時會收到一下報錯:

File "./hello_world.py", line 2
SyntaxError: Non-ASCII character '\xe4' in file ./hello_world.py on line 2, but no encoding declared; see //www.python.org/peps/pep-0263.html for details

錯誤提示的意思就是存在非ASCII字元,但是卻沒有encoding declared,同時給了一個連接並說明包含詳細原因,這個鏈接是一個PEP(python enhancement proper)。
enter image description here

這個PEP的內容總結下來就是:
這行程式碼用於聲明程式碼文件的編碼格式,這個資訊可以幫助python解析器使用指定的正確編碼來解釋程式碼文件。這樣就可以允許直接在程式碼中使用utf-8編碼了。
另外需要注意的是:聲明的編碼格式要和程式碼文件的格式一樣才行,否則會報錯。

來看另外一個例子:

# -*- coding:utf-8 -*-
print('你好 python')

將這段程式碼保存為ANSI格式,並執行,會得到以下報錯:

$ python ./hello_python.py
  File "./hello_python.py", line 2
SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

所以說指定編碼的時候也不能全部統一指定為utf-8,而是要根據源碼文件的格式來指定,兩者要一致才行。

另外又在python的官方文檔找到一個說明:
enter image description here
意思就是說:默認情況下,python解釋器(python2)把源程式碼文件當做ASCII編碼來處理,如果源碼文件是其他格式就需要通過一個特殊的注釋來說明,也就是:coding:utf-8,當然編碼格式支援多中,具體看codecs的支援情況。
這裡其實也是由於python誕生的太早了,那時候Unicode都還沒有誕生,因此當時作者也只能選擇ASCII作為默認的編碼格式。python3已經將默認編碼格式改為UTF-8

總結

所以總結下來就是,python2中,該行程式碼的作用是當源程式碼文件不是ASCII編碼時,通過該行程式碼告訴python解釋器正確的編碼格式,這樣python解釋器才能正常解釋其中的字元。
另外,由於python3已經修改為默認情況下,將源程式碼文件當做UTF-8格式來處理,同時我們寫程式碼時現在通常都會使用UTF-8格式來存儲,因此python3其實是不用再寫這一行程式碼的,除非你的源程式碼文件不是UTF-8格式的。

二、sys.setdefaultencoding(‘utf-8’)

先來看一個例子:

# -*- coding:utf-8 -*-
s = '你好'
s.encode('gb2312')

執行以上程式碼會收到下面的報錯:

Traceback (most recent call last):
  File "./hello_str.py", line 3, in <module>
    s.encode('gb2312')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

第一次遇到這個報錯時,感覺很奇怪,明明我做的是encode操作,但是為什麼報錯確實decode失敗呢?
這裡就是先提一下了:Python裡面的編碼和解碼也就是unicode和str這兩種形式的相互轉化。編碼是unicode->str,相反的,解碼就是str->unicode。
而上面定義的s是str類型的,因此當調用encode時,其實默認是先做了decode,轉換為Unicode,然後再執行encode編碼為指定的編碼的,這裡報錯的原因就是當做隱式編碼、解碼時使用的默認格式是:ASCII,但是由於s是utf-8的編碼,所以解碼就失敗了。
解決辦法:
1、在文件頭部添加sys.setdefaultencoding(‘utf-8’)修改默認的編碼、解碼格式。

import sys
sys.setdefaultencoding('utf-8')

2、避免由程式做隱式的編碼、解碼,也就是說要明確str-Unicode的轉換規則,但是需要編碼時要確認類型是Unicode,如果不是就手動指定正確的解碼格式轉換為Unicode。

s.decode('utf-8').encode('gb2312')

總結

setdefaultencoding主要在編碼、解碼沒有明確指明編碼、解碼格式的時候使用。

三、參考資料

1、PEP 263
2、source-code-encoding

Tags: