Python3中的bytes和str類型詳解
Python 3最重要的新特性之一是對(duì)字符串和二進(jìn)制數(shù)據(jù)流做了明確的區(qū)分。文本總是Unicode,由str類型表示,二進(jìn)制數(shù)據(jù)則由bytes類型表示。Python 3不會(huì)以任意隱式的方式混用str和bytes,你不能拼接字符串和字節(jié)流,也無法在字節(jié)流里搜索字符串(反之亦然),也不能將字符串傳入?yún)?shù)為字節(jié)流的函數(shù)(反之亦然)。
下面讓我們深入分析一下二者的區(qū)別和聯(lián)系。
編碼發(fā)展的歷史
在談bytes和str之前,需要先說說關(guān)于編碼是如何發(fā)展的。。
在計(jì)算機(jī)歷史的早期,美國(guó)為代表的英語(yǔ)系國(guó)家主導(dǎo)了整個(gè)計(jì)算機(jī)行業(yè),26個(gè)英文字母組成了多樣的英語(yǔ)單詞、語(yǔ)句、文章。因此,最早的字符編碼規(guī)范是ASCII碼,一種8位即1個(gè)字節(jié)的編碼規(guī)范,它可以涵蓋整個(gè)英語(yǔ)系的編碼需要。
編碼是什么?編碼就是把一個(gè)字符用一個(gè)二進(jìn)制來表示。我們都知道,所有的東西,不管是英文、中文還是符號(hào)等等,最終存儲(chǔ)在磁盤上都是01010101這類東西。在計(jì)算機(jī)內(nèi)部,讀取和存儲(chǔ)數(shù)據(jù)歸根結(jié)底,處理的都是0和1組成的比特流。問題來了,人類看不懂這些比特流,如何讓這些010101對(duì)人類變得可讀呢?于是出現(xiàn)了字符編碼,它是個(gè)翻譯機(jī),在計(jì)算機(jī)內(nèi)部某個(gè)地方,透明的幫我們將比特流翻譯成人類可以直接理解的文字。對(duì)于一般用戶,不需要知道這個(gè)過程是什么原理,是怎么執(zhí)行的。但是對(duì)于程序員卻是個(gè)必須搞清楚的問題。
以ASCII編碼為例,它規(guī)定1個(gè)字節(jié)8個(gè)比特位代表1個(gè)字符的編碼,也就是“00000000”這么寬,一個(gè)一個(gè)字節(jié)的解讀。例如:01000001表示大寫字母A,有時(shí)我們會(huì)“偷懶"的用65這個(gè)十進(jìn)制來表示A在ASCII中的編碼。8個(gè)比特位,可以沒有重復(fù)的最多表示2的8次方(255)個(gè)字符。
后來,計(jì)算機(jī)得到普及,中文、日文、韓文等等國(guó)家的文字需要在計(jì)算機(jī)內(nèi)表示,ASCII的255位遠(yuǎn)遠(yuǎn)不夠,于是標(biāo)準(zhǔn)組織制定出了叫做UNICODE的萬(wàn)國(guó)碼,它規(guī)定任何一個(gè)字符(不管哪國(guó)的)至少以2個(gè)字節(jié)表示,可以更多。其中,英文字母就是用2個(gè)字節(jié),而漢字是3個(gè)字節(jié)。這個(gè)編碼雖然很好,滿足了所有人的要求,但是它不兼容ASCII,同時(shí)還占用較多的空間和內(nèi)存。因?yàn)?,在?jì)算機(jī)世界更多的字符是英文字母,明明可以1個(gè)字節(jié)就能夠表示,非要用2個(gè)。
于是UTF-8編碼應(yīng)運(yùn)而生,它規(guī)定英文字母系列用1個(gè)字節(jié)表示,漢字用3個(gè)字節(jié)表示等等。因此,它兼容ASCII,可以解碼早期的文檔。UTF-8很快就得到了廣泛的應(yīng)用。
在編碼的發(fā)展歷程中,我國(guó)還創(chuàng)造了自己的編碼方式,例如GBK,GB2312,BIG5。他們只局限于在國(guó)內(nèi)使用,不被國(guó)外認(rèn)可。在GBK編碼中,中文漢字占2個(gè)字節(jié)。
bytes和str之間的異同
回到bytes和str的身上。bytes是一種比特流,它的存在形式是01010001110這種。我們無論是在寫代碼,還是閱讀文章的過程中,肯定不會(huì)有人直接閱讀這種比特流,它必須有一個(gè)編碼方式,使得它變成有意義的比特流,而不是一堆晦澀難懂的01組合。因?yàn)榫幋a方式的不同,對(duì)這個(gè)比特流的解讀也會(huì)不同,對(duì)實(shí)際使用造成了很大的困擾。下面讓我們看看Python是如何處理這一系列編碼問題的:
>>> s = "中文" >>> s '中文' >>> type(s) <class 'str'> >>> b = bytes(s, encoding='utf-8') >>> b b'\xe4\xb8\xad\xe6\x96\x87' #\x 代表是十六進(jìn)制 >>> type(b) <class 'bytes'>
從例子可以看出,s是個(gè)字符串類型。Python有個(gè)內(nèi)置函數(shù)bytes()可以將字符串str類型轉(zhuǎn)換成bytes類型,b實(shí)際上是一串01的組合,但為了在ide環(huán)境中讓我們相對(duì)直觀的觀察,它被表現(xiàn)成了b'\xe4\xb8\xad\xe6\x96\x87'這種形式,開頭的b表示這是一個(gè)bytes類型。\xe4是十六進(jìn)制的表示方式,它占用1個(gè)字節(jié)的長(zhǎng)度,因此”中文“被編碼成utf-8后,我們可以數(shù)得出一共用了6個(gè)字節(jié),每個(gè)漢字占用3個(gè),這印證了上面的論述。在使用內(nèi)置函數(shù)bytes()的時(shí)候,必須明確encoding的參數(shù),不可省略。
我們都知道,字符串類str里有一個(gè)encode()方法,它是從字符串向比特流的編碼過程。而bytes類型恰好有個(gè)decode()方法,它是從比特流向字符串解碼的過程。除此之外,我們查看Python源碼會(huì)發(fā)現(xiàn)bytes和str擁有幾乎一模一樣的方法列表,最大的區(qū)別就是encode和decode。
從實(shí)質(zhì)上來說,字符串在磁盤上的保存形式也是01的組合,也需要編碼解碼。
如果,上面的闡述還不能讓你搞清楚兩者的區(qū)別,那么記住下面兩幾句話:
在將字符串存入磁盤和從磁盤讀取字符串的過程中,Python自動(dòng)地幫你完成了編碼和解碼的工作,你不需要關(guān)心它的過程。
使用bytes類型,實(shí)質(zhì)上是告訴Python,不需要它幫你自動(dòng)地完成編碼和解碼的工作,而是用戶自己手動(dòng)進(jìn)行,并指定編碼格式。
Python已經(jīng)嚴(yán)格區(qū)分了bytes和str兩種數(shù)據(jù)類型,你不能在需要bytes類型參數(shù)的時(shí)候使用str參數(shù),反之亦然。這點(diǎn)在讀寫磁盤文件時(shí)容易碰到。
在bytes和str的互相轉(zhuǎn)換過程中,實(shí)際就是編碼解碼的過程,必須顯式地指定編碼格式。
>>> b b'\xe4\xb8\xad\xe6\x96\x87' >>> type(b) <class 'bytes'>
>>> s1 = str(b) >>> s1 "b'\\xe4\\xb8\\xad\\xe6\\x96\\x87'" #注意這里 >>> type(s1) <class 'str'>
>>> s1 = str(b, encoding='utf-8') >>> s1 '中文' >>> type(s1) <class 'str'>
我們?cè)侔炎址畇1,轉(zhuǎn)換成gbk編碼的bytes類型:
>>> s1 '中文' >>> type(s1) <class 'str'> >>> b = bytes(s1, encoding='gbk') >>> b
編碼可以將抽象字符以二進(jìn)制數(shù)據(jù)的形式表示,有很多編碼方法,如utf-8、gbk等,可以使用encode()函數(shù)對(duì)字符串進(jìn)行編碼,轉(zhuǎn)換成二進(jìn)制字節(jié)數(shù)據(jù),也可用decode()函數(shù)將字節(jié)解碼成字符串;用decode()函數(shù)解碼,可不要用指定編碼格式;
>>> a = 'hello world' >>> type(a) <class 'str'> >>> a 'hello world'
a. 按utf-8的方式編碼,轉(zhuǎn)成bytes:以及解碼成字符串
#a為串'hello world' >>> b = a.encode(encoding='utf-8') >>> type(b) <class 'bytes'> >>> >>> b b'hello world' >>> >>> >>> c = b.decode(encoding='utf-8') >>> type(c) <class 'str'> >>> c 'hello world'
b. 按gbk的方式編碼,轉(zhuǎn)成bytes:以及解碼成字符串
path="doc.txt" f=open(path,'rb') raw=f.read() print(raw[:100]) print(len(raw)) print(type(raw)) raw1=str(raw) print(raw1[:100]) print(len(raw1)) print(type(raw1)) tokens=word_tokenize(raw1) print(len(tokens)) print(tokens[:20])
b'the rock is destined to be the 21st century\'s new " conan " and that he\'s going to make a splash eve' 626168 <class 'bytes'> b'the rock is destined to be the 21st century\'s new " conan " and that he\'s going to make a splash 634857 <class 'str'> 115104 ["b'the", 'rock', 'is', 'destined', 'to', 'be', 'the', '21st', 'century\\', "'s", 'new', '``', 'conan', '``', 'and', 'that', 'he\\', "'s", 'going', 'to']
from nltk import word_tokenize path="doc.txt" f=open(path,'rb') raw=f.read() print(raw[:1000]) print(len(raw)) print(type(raw)) raw=raw[:1000] raw1= raw.decode(encoding='utf-8') #在4000多的位置上有無法解碼的,也就是說解碼方式是有問題的,應(yīng)該不是utf-8 print(raw1[:1000]) print(len(raw1)) print(type(raw1))
b'the rock is destined to be the 21st century\'s new " conan " and that he\'s going to make a splash even greater than arnold schwarzenegger , jean-claud van damme or steven segal . \nthe gorgeously elaborate continuation of " the lord of the rings " trilogy is so huge that a column of words cannot adequately describe co-writer/director peter jackson\'s expanded vision of j . r . r . tolkien\'s middle-earth . \neffective but too-tepid biopic\nif you sometimes like to go to the movies to have fun , wasabi is a good place to start . \nemerges as something rare , an issue movie that\'s so honest and keenly observed that it doesn\'t feel like one . \nthe film provides some great insight into the neurotic mindset of all comics -- even those who have reached the absolute top of the game . \noffers that rare combination of entertainment and education . \nperhaps no picture ever made has more literally showed that the road to hell is paved with good intentions . \nsteers turns in a snappy screenplay that curl' 626168 <class 'bytes'> the rock is destined to be the 21st century's new " conan " and that he's going to make a splash even greater than arnold schwarzenegger , jean-claud van damme or steven segal . the gorgeously elaborate continuation of " the lord of the rings " trilogy is so huge that a column of words cannot adequately describe co-writer/director peter jackson's expanded vision of j . r . r . tolkien's middle-earth . effective but too-tepid biopic if you sometimes like to go to the movies to have fun , wasabi is a good place to start . emerges as something rare , an issue movie that's so honest and keenly observed that it doesn't feel like one . the film provides some great insight into the neurotic mindset of all comics -- even those who have reached the absolute top of the game . offers that rare combination of entertainment and education . perhaps no picture ever made has more literally showed that the road to hell is paved with good intentions . steers turns in a snappy screenplay that curl 1000 <class 'str'> 189 ['e', 'rock', 'is', 'destined', 'to', 'be', 'the', '21st', 'century', "'s", 'new', '``', 'conan', '``', 'and', 'that', 'he', "'s", 'going', 'to']
將a(字符串)進(jìn)行編碼,當(dāng)a為中文時(shí),將Unicode編碼為b'\\u4f60\\u597d',輸入b顯示時(shí),python自動(dòng)假設(shè)unicode字符的默認(rèn)編碼方式是ASCII,但ASCII中沒有b'\\u4f60\\u597d',所以就直接輸出了。
當(dāng)a為'hello'時(shí),編碼為(也是數(shù)字),但print時(shí)可以按照ASCII的形式顯示bytes類型。
>>>a='你好' >>>b=a.encode('unicode_escape') >>>b b'\\u4f60\\u597d' >>>a='hello' >>>b=a.encode('unicode_escape') >>>b b'hello'
以上所述是小編給大家介紹的Python3中的bytes和str類型詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
python正則表達(dá)式之對(duì)號(hào)入座篇
正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯2018-07-07Python中xml和dict格式轉(zhuǎn)換的示例代碼
最近在做APP的接口,遇到XML格式的請(qǐng)求數(shù)據(jù),費(fèi)了很大勁來解決,下面小編給大家分享下Python中xml和dict格式轉(zhuǎn)換問題,感興趣的朋友跟隨小編一起看看吧2019-11-11NumPy實(shí)現(xiàn)多維數(shù)組中的線性代數(shù)
本文主要介紹了NumPy實(shí)現(xiàn)多維數(shù)組中的線性代數(shù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07Python入門教程(二十二)Python的類和對(duì)象
這篇文章主要介紹了Python入門教程(二十二)Python的類和對(duì)象,Python是一門非常強(qiáng)大好用的語(yǔ)言,也有著易上手的特性,本文為入門教程,需要的朋友可以參考下2023-04-04Python基于callable函數(shù)檢測(cè)對(duì)象是否可被調(diào)用
這篇文章主要介紹了Python基于callable函數(shù)檢測(cè)對(duì)象是否可被調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10python設(shè)計(jì)tcp數(shù)據(jù)包協(xié)議類的例子
今天小編就為大家分享一篇python設(shè)計(jì)tcp數(shù)據(jù)包協(xié)議類的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07基于Python腳本實(shí)現(xiàn)郵件報(bào)警功能
這篇文章主要介紹了基于Python腳本實(shí)現(xiàn)郵件報(bào)警功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Python實(shí)現(xiàn)桌面翻譯工具【新手必學(xué)】
這篇文章主要介紹了Python實(shí)現(xiàn)一個(gè)桌面翻譯工具,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02