字符串類型:str, bytes 的區別


Python 3最重要的新特性之一是對字符串和二進制數據流做了明確的區分

  • 文本總是 Unicode,由 str 類型表示,
  • 二進制數據則由 bytes 類型表示。

Python 3不會以任意隱式的方式混用strbytes,你不能拼接字符串和字節流,也無法在字節流里搜索字符串(反之亦然),

也不能將字符串傳入參數為字節流的函數(反之亦然)。

下面讓我們深入分析一下二者的區別和聯系。

  在計算機歷史的早期,美國為代表的英語系國家主導了整個計算機行業,26個英文字母組成了多樣的英語單詞、語句、文章。

因此,最早的字符編碼規范是ASCII碼,一種8位即1個字節的編碼規范,它可以涵蓋整個英語系的編碼需要。

編碼是什么?編碼就是把一個字符用一個二進制來表示。

  我們都知道,所有的東西,不管是英文、中文還是符號等等,最終存儲在磁盤上都是01010101這類東西。在計算機內部,讀取和存儲數據歸根結底,處理的都是0和1組成的比特流。問題來了,人類看不懂這些比特流,如何讓這些010101對人類變得可讀呢?

於是出現了字符編碼,它是個翻譯機,在計算機內部某個地方,透明的幫我們將比特流翻譯成人類可以直接理解的文字。

  對於一般用戶,不需要知道這個過程是什么原理,是怎么執行的。但是對於程序員卻是個必須搞清楚的問題。

ASCII編碼為例,它規定1個字節8個比特位代表1個字符的編碼,也就是“00000000”這么寬,逐個字節的解讀。例如:

  • 01000001表示大寫字母A,有時我們會“偷懶"的用 65 這個十進制來表示A在ASCII中的編碼。8個比特位,最多可表示2的8次方(255)個字符。

后來,計算機得到普及,中文、日文、韓文等等國家的文字需要在計算機內表示,ASCII的255位遠遠不夠,於是標准組織制定出了叫做UNICODE的萬國碼

它規定任何一個字符(不管哪國的)至少以2個字節表示,可以更多

  其中,英文字母就是用2個字節,而漢字是3個字節。這個編碼雖然很好,滿足了所有人的要求,但是它不兼容ASCII,同時還占用較多的空間和內存,不便於網絡傳輸文件存儲。因為,在計算機世界更多的字符是英文字母,明明可以1個字節就能夠表示,非要用2個。

於是UTF-8編碼應運而生,它規定

  • 英文字母系列用1個字節表示,
  • 歐洲文字通常用兩個字節表示,
  • (CJK 統一表意符號 (CJK Unified Ideographs):4E00-9FBF)漢字等東亞文字用3個字節表示等等。

因此,它兼容ASCII,可以解碼早期的文檔。UTF-8很快就得到了廣泛的應用。

在編碼的發展歷程中,我國還創造了自己的編碼方式,例如GBKGB2312BIG5。他們只局限於在國內使用,不被國外認可。在GBK編碼中,中文漢字占2個字節。

bytes和str之間的異同

bytes是一種比特流,它的存在形式是01010001110這種。我們無論是在寫代碼,還是閱讀文章的過程中,肯定不會有人直接閱讀這種比特流,它必須有一個編碼方式,使得它變成有意義的比特流,而不是一堆晦澀難懂的01組合。因為編碼方式的不同,對這個比特流的解讀也會不同,對實際使用造成了很大的困擾。

下面讓我們看看Python是如何處理這一系列編碼問題的:

 1 >>> str1 = '學無定法而有方法'
 2 >>> str1
 3 '學無定法而有方法'
 4 >>> type(str1)
 5 <class 'str'>
 6 >>> b1 = bytes(str1, encoding='utf-8')
 7 >>> b1
 8 b'\xe5\xad\xa6\xe6\x97\xa0\xe5\xae\x9a\xe6\xb3\x95\xe8\x80\x8c\xe6\x9c\x89\xe6\x96\xb9\xe6\xb3\x95'
 9 >>> type(b1)
10 <class 'bytes'>
11 >>> 

  從例子可以看出,str1是個字符串類型。Python有個內置函數bytes()可以將字符串str類型轉換成bytes類型,

b1實際上是一串01的組合,但為了在ide環境中讓我們相對直觀的觀察,它被表現成了

b'\xe5\xad\xa6\xe6\x97\xa0\xe5\xae\x9a\xe6\xb3\x95\xe8\x80\x8c\xe6\x9c\x89\xe6\x96\xb9\xe6\xb3\x95'這種形式,

  • 開頭的b表示這是一個bytes類型。
  • \xe5十六進制的表示方式,它占用1個字節的長度,

因此”學無定法而有方法“被編碼成utf-8后,我們可以數得出一共用了24個字節,每個漢字占用3個。

 

  在使用內置函數bytes()的時候,必須明確encoding的參數,不可省略。

  我們都知道,字符串類str里有一個encode()方法,它是從字符串向比特流的編碼過程。

  而bytes類型恰好有個decode()方法,它是從比特流向字符串解碼的過程。

  除此之外,我們查看Python源碼會發現bytesstr擁有幾乎一模一樣的方法列表,最大的區別就是 encode 和 decode 

從實質上來說,字符串在磁盤上的保存形式也是01的組合,也需要編碼解碼。

如果,上面的闡述還不能讓你搞清楚兩者的區別,那么記住下面兩幾句話:

  1. 在將字符串存入磁盤從磁盤讀取字符串的過程中,Python自動地幫你完成了編碼解碼的工作。
  2. 使用bytes類型,實質上是告訴Python,不需要它幫你自動地完成編碼和解碼的工作,而是用戶自己手動進行,並指定編碼格式。
  3. Python已經嚴格區分了bytesstr兩種數據類型,你不能在需要bytes類型參數的時候使用str參數,反之亦然。
  4. 圖片、視頻等文件通常是以bytes類型讀寫的,所以類型通常是rb, wb模式

bytesstr的互相轉換過程中,實際就是編碼解碼的過程,必須顯式地指定編碼格式

 1 >>> b2 = str1[:2].encode('gbk')
 2 >>> b2
 3 b'\xd1\xa7\xce\xde'
 4 >>> b2.decode('gbk')
 5 '學無'
 6 >>> b3 = str1[:2].encode('utf-8')
 7 >>> b3
 8 b'\xe5\xad\xa6\xe6\x97\xa0'
 9 >>> b3.decode('utf-8')
10 '學無'
11 >>> str2 = 'こんにちは'
12 >>> b4 = str2.encode('shift-jis')
13 >>> b4
14 b'\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd'
15 >>> b4.decode('shift-jis')
16 'こんにちは'
17 >>> 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM