【python測試開發棧】帶你完全搞明白python3編碼原理

在以前的文章中,咱們介紹過編碼格式的發展史:[文章傳送門-todo]。今天咱們經過幾個例子,來完全搞清楚python3中的編碼格式原理,這樣你以後寫python腳本時碰到編碼問題,纔能有章可循。python

咱們先搞清楚幾個概念:linux

  • 系統默認編碼:指python解釋器默認的編碼格式,在python文件頭部沒有聲明其餘編碼格式時,python3默認的編碼格式是utf-8。
  • 本地默認編碼:操做系統默認的編碼,常見的Windows的默認編碼是gbk,Linux的默認編碼是UTF-8。
  • python文件頭部聲明編碼格式:修改的是文件的默認編碼格式,只是會影響python解釋器讀取python文件時的編碼格式,並不會改變系統默認編碼和本地默認編碼。

經過python自帶的庫,能夠查看系統默認編碼和本地默認編碼shell

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
>>> import locale
>>> locale.getdefaultlocale()
('zh_CN', 'cp936')
>>>

注意,由於我在windows系統的電腦上 進行測試,因此係統默認編碼返回「cp936」, 這是代碼頁(是字符編碼集的別名),而936對應的就是gbk。若是你在linux或者mac上執行上面的代碼,應該會返回utf-8編碼。windows

其實總結來看,容易出現亂碼的場景,基本都與讀寫程序有關,好比:讀取/寫入某個文件,或者從網絡流中讀取數據等,由於這個過程當中涉及到了編碼解碼的過程,只要編碼和解碼的編碼格式對應不上,就容易出現亂碼。下面咱們舉兩個具體的例子,來驗證下python的編碼原理,幫助你理解這個過程。注意:下面的例子都是在pycharm中寫的。bash

01默認的編碼格式

咱們新建一個encode_demo.py的文件,其文件默認的編碼格式是UTF-8(能夠從pycharm右下角看到編碼格式),代碼以下:網絡

"""
    @author: asus
    @time: 2019/11/21
    @function: 驗證編碼格式
"""
import sys, locale


def write_str_default_encode():
    s = "我是一個str"
    print(s)
    print(type(s))
    print(sys.getdefaultencoding())
    print(locale.getdefaultlocale())

    with open("utf_file", "w", encoding="utf-8") as f:
        f.write(s)
    with open("gbk_file", "w", encoding="gbk") as f:
        f.write(s)
    with open("jis_file", "w", encoding="shift-jis") as f:
        f.write(s)


if __name__ == '__main__':
    write_str_default_encode()

咱們先來猜想下結果,由於咱們沒有聲明編碼格式,因此python解釋器默認用UTF-8去解碼文件,由於文件默認編碼格式就是UTF-8,因此字符串s能夠正常打印。同時以UTF-8編碼格式寫文件不會出現亂碼,而以gbk和shift-jis(日文編碼)寫文件會出現亂碼(這裏說明一點,我是用pycharm直接打開生成的文件查看的,編輯器默認編碼是UTF-8,若是在windows上用記事本打開則其默認編碼跟隨系統是GBK,gbk_file和utf_file均不會出現亂碼,只有jis_file是亂碼),咱們運行看下結果:編輯器

# 運行結果
我是一個str
<class 'str'>
utf-8
('zh_CN', 'cp936')

# 寫文件utf_file、gbk_file、jis_file文件內容分別是:
我是一個str
����һ��str
�䐥�꘢str

和咱們猜想的結果一致,下面咱們作個改變,在文件頭部聲明個編碼格式,再來看看效果。測試

02 python頭文件聲明編碼格式

由於上面文件encode_demo.py的格式是UTF-8,那麼咱們就將其變爲gbk編碼。一樣的咱們先來推測下結果,在pycharm中,在python文件頭部聲明編碼爲gbk後(頭部加上 # coding=gbk ),文件的編碼格式變成gbk,同時python解釋器會用gbk去解碼encode_demo.py文件,因此運行結果應該和用UTF-8編碼時同樣。運行結果以下:編碼

# 運行結果
我是一個str
<class 'str'>
utf-8
('zh_CN', 'cp936')

# 寫文件utf_file、gbk_file、jis_file文件內容分別是:
我是一個str
����һ��str
�䐥�꘢str

結果確實是同樣的,證實咱們推論是正確的。接下來咱們再作個嘗試,假如咱們將(# coding=gbk)去掉(須要注意,在pycharm中將 # coding=gbk去掉,並不會改變文件的編碼格式,也就是說encode_demo.py仍是gbk編碼),咱們再運行一次看結果:spa

File "D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py", line 4
SyntaxError: Non-UTF-8 code starting with '\xd1' in file D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py on line 5, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

運行直接報錯了,咱們加個斷點,看看具體的異常信息:

編碼錯誤.png

看錯誤提示是UnicodeDecodeError,python解釋器在對encode_demo.py文件解碼時,使用默認的UTF-8編碼,可是文件自己是gbk編碼,因此當碰到有中文沒辦法識別時,就拋出DecodeError。

03 敲黑板,劃重點

python3中的str和bytes

python3的重要特性之一就是對字符串和二進制流作了嚴格的區分,咱們聲明的字符串都是str類型,不過Str和bytes是能夠相互轉換的:

def str_transfor_bytes():
    s = '我是一個測試Str'
    print(type(s))
    # str 轉bytes
    b = s.encode()
    print(b)
    print(type(b))
    # bytes轉str
    c = b.decode('utf-8')
    print(c)
    print(type(c))


if __name__ == '__main__':
    str_transfor_bytes()

須要注意一點:在調用encode()和decode()方法時,若是不傳參數,則會使用python解釋器默認的編碼格式UTF-8(若是不在python頭文件聲明編碼格式)。可是若是傳參的話,encode和decode使用的編碼格式要能對應上。

python3默認編碼是UTF-8?仍是Unicode?

常常在不少文章裏看到,python3的默認編碼格式是Unicode,可是我在本文中卻一直在說python3的默認編碼格式是UTF-8,那麼哪一種說法是正確的呢?其實兩種說法都對,主要得搞清楚Unicode和UTF-8的區別(以前文章有提到):

  • Unicode是一個字符集,說白了就是把各類編碼的映射關係全都整合起來,不過它是不可變長的,所有都以兩個字節或四個字節來表示,佔用的內存空間比較大。
  • UTF-8是Unicode的一種實現方式,主要對 Unicode 碼的數據進行轉換,方便存儲和網絡傳輸 。它是可變長編碼,好比對於英文字母,它使用一個字節就能夠表示。

在python3內存中使用的字符串全都是Unicode碼,當python解釋器解析python文件時,默認使用UTF-8編碼。

open()方法默認使用本地編碼

在上面的例子中,咱們往磁盤寫入文件時,都指定了編碼格式。若是不指定編碼格式,那麼默認將使用操做系統本地默認的編碼格式,好比:Linux默認是UTF-8,windows默認是GBK。其實這也好理解,由於和磁盤交互,確定要考慮操做系統的編碼格式。這有區別於encode()和decode()使用的是python解釋器的默認編碼格式,千萬別搞混淆了。

總結

不知道你看完上面的例子後,是否已經完全理解了python3的編碼原理。不過全部的編碼問題,都逃不過「編碼」和「解碼」兩個過程,當你碰到編碼問題時,先肯定源文件使用的編碼,再肯定目標文件須要的編碼格式,只要能匹配,通常就能夠解決編碼的問題。

相關文章
相關標籤/搜索