Python2和python3字符編碼的區別

Python2和python3字符編碼的區別

一、字符編碼應用值Python

1. 執行Python程序的三個階段

Python test.py(執行test.py的第一步,一定是先將文件內容從硬盤讀入到內存中 )

text.py文件內容以gbk格式保存的,內容爲:

  • 階段一:啓動python解釋器
  • 階段二:Python解釋器此時就是一個文本編輯器,負責打開文件test.py,即衝硬盤中讀取test.py的內容到內存中

此時,Python解釋器會讀取test.py的第一行內容,#coding:utf8 或 #-*-coding:utf-8-*-,以此決定什麼編碼格式將代碼讀入內存,這一行就是設定Python解釋器這個軟件使用 的編碼格式。

可以用sys.getdefaultencoding()查看,如果不在Python文件指定頭信息#-*-coding:utf-8-*-,那就使用Python默認的編碼格式。

import sys
sys.getdefaultencoding()

utf8

Python2中默認使用ascii,Python3中默認使用utf-8。

改正:在test.py制定文件頭,字符編碼一定要爲gbk。即更正爲

#coding:gbk
你好啊

  • 階段三:讀取已經加載到內存的代碼(Unicode編碼格式),然後執行執行過程中肯會開闢一個新的內存空間,比如name="nick"

內存的編碼使用Unicode,不代表內存中全是Unicode,因爲在程序執行之前,內存中確實都是Unicode,比如從文件中讀取了一行name='nick',其中的那麼、等號、引號的地位都一樣,都是普通字符而已,都是以Unicode的格式存放於內存中的。

但是程序在執行過程中,會申請內存(與程序代碼所存在的內存是倆個空間)用來存放Python的數據類型的值,而Python的字符串類型又涉及到了字符的概念。

比如name="nick",會被Python解釋器識別爲字符串,會申請內存空間來存放字符串類型的值,至於該字符串類型的值被識別成何種編碼存放,這就與Python解釋器的有關了,而Python2與Python3的字符串類型又有所不同。

二、Python2與Python3字符串類型的區別

1. python2

在Python2中有兩種字符串類型str和Unicode。

1.1 str類型

當Python解釋器執行到產生字符串的代碼時(例如x='上'),會申請新的內存地址,然後將'上'編碼成文件開頭指定的編碼格式

因爲直接print()會自動轉換編碼,我們使用encode()方法查看'上'的字符編碼。

# 三、Python2中代碼

# 四、coding:gbk

x = '上'
y = '下'
print([x, y])  # ['\xc9\xcf', '\xcf\xc2']
# 五、\x代表16進制,此處是c9cf總共4位16進制數,一個16進制四4個比特位,4個16進制數則是16個比特位,即2個Bytes,這就證明了按照gbk編碼中文用2Bytes

print(type(x),type(y))  # (<type 'str'>, <type 'str'>)

理解字符編碼的關鍵!!!

內存中的數據通常用16進製表示,2位16進制數據代表一個字節,如\xc9,代表兩位16進制,一個字節

gbk存中文需要2個bytes,而存英文則需要1個bytes,它是如何做到的???!!!

gbk會在每個bytes,即8位bit的第一個位作爲標誌位,標誌位爲1則表示是中文字符,如果標誌位爲0則表示爲英文字符。

x='你a好'

轉成gbk格式二進制位:8bit+8bit+8bit+8bit+8bit=(1+7bit)+(1+7bit)+(0+7bit)+(1+7bit)+(1+7bit)

樣計算機按照從左往右的順序讀:

  1. 連續讀到前兩個括號內的首位標誌位均爲1,則構成一箇中午字符:你
  2. 讀到第三個括號的首位標誌爲0,則該8bit代表一個英文字符:a
  3. 連續讀到後兩個括號內的首位標誌位均爲1,則構成一箇中午字符:好

也就是說,每個Bytes留給我們用來存真正值的有效位數只有7位,而在Unicode表中存放的只是這有效的7位,至於首位的標誌位與具體的編碼有關,即在Unicode中表示gbk的方式爲:(7bit)+(7bit)+(7bit)+(7bit)+(7bit)

按照上圖翻譯的結果,我們可以去Unicode關於漢字的對應關係中去查:鏈接:https://pan.baidu.com/s/1dEV3RYp

可以看到“上”對應的gbk(G0代表的是gbk)編碼就爲494F,即我們得出的結果,而上對應的Unicode編碼爲4E0A,我們可以將gbk-->decode-->Unicode。

# 六、Python2中代碼

# 七、coding:gbk

x = '上'.decode('gbk')
y = '下'.decode('gbk')
print([x, y])  # [u'\u4e0a', u'\u4e0b']

1.2 Unicode類型

當Python解釋器執行到產生字符串的代碼時(例如s=u'林'),會申請新的內存地址,然後將'林'以Unicode的格式存放到新的內存空間中,所以s只能encode,不能decode。

# 八、Python2中代碼

# 九、coding:gbk

x = u'上'  # 等同於 x='上'.decode('gbk')
y = u'下'  # 等同於 y='下'.decode('gbk')
print([x, y])  # [u'\u4e0a', u'\u4e0b']
print(type(x),type(y))  # (<type 'Unicode'>, <type 'Unicode'>)

對於print需要特別說明的是:當程序執行時,比如x='上' # gbk下,字符串存放爲\xc9\xcf

print(x)這一步是將x指向的那塊新的內存空間(非代碼所在的內存空間)中的內存,打印到終端,按理說應該是存的什麼就打印什麼,但打印\xc9\xcf,對一些不熟知Python編碼的程序員,立馬就懵逼了,所以龜叔自作主張,在print(x)時,使用終端的編碼格式,將內存中的\xc9\xcf轉成字符顯示,此時就需要終端編碼必須爲gbk,否則無法正常顯示原內容:上。

對於Unicode格式的數據來說,無論怎麼打印,都不會亂碼

Unicode這麼好,不會亂碼,那Python2爲何還那麼彆扭,搞一個str出來呢?Python誕生之時,Unicode並未像今天這樣普及,很明顯,好的東西你能看得見,龜叔早就看見了,龜叔在Python3中將str直接存成Unicode,我們定義一個str,無需是否加u前綴,就是一個Unicode,屌不屌?

2. Python3

Python3中str都是Unicode編碼的,所以Python3中的str類型的數據可以編碼成其他字符編碼的格式,編碼的結果爲bytes類型

# coding:gbk
x = '上'  # 當程序執行時,無需加u,'上'也會被以Unicode形式保存新的內存空間中,

print(f"type(x): {type(x)}")  # <class 'str'>

# x可以直接encode成任意編碼格式
print(f"x.encode('gbk'): {x.encode('gbk')}")  # b'\xc9\xcf'
print(f"type(x.encode('gbk')): {type(x.encode('gbk'))}")  # <class 'bytes'>

type(x): <class 'str'> x.encode('gbk'): b'\xc9\xcf' type(x.encode('gbk')): <class 'bytes'>

很重要的一點是:看到Python3中x.encode('gbk') 的結果\xc9\xcf正是Python2中的str類型的值,而在Python3是bytes類型,在Python2中則是str類型。

三、總而言之

代碼詳情 Python2執行情況 Python3執行情況
# coding:gbk print('中') 終端:utf8 亂碼 不亂碼
# coding:utf8 print('中') 終端:utf8 不亂碼 不亂碼
# coding:gbk print(u'中') 終端:utf8 不亂碼 不亂碼
# coding:utf8 print(u'中') 終端:utf8 不亂碼 不亂碼

在Python2中如果指定了字符編碼,那麼內存存取就會按照指定的字符編碼去入內存。解釋或去執行時就要按照指定了的字符編碼去解釋,否則就會亂碼。 否則可以在定義變量前面加上u,這樣變量就會以unicode編碼存入內存。

如:

#coding:gbk

name = "爸爸"

但在Python3中就不會有這樣的問題,因爲無論你指定了什麼字符編碼,在內存存取時都會使用Unicode編碼去入內存,Unicode編碼可以和任意的字符編碼相互轉換,並在讀取時按照所需的編碼區讀取,這樣就很好解決了字符編碼的問題

 

注意:

保存文件到電腦硬盤的編碼格式必須要和文件開頭指定的編碼格式#coding:gbk一致,否則會報異常。

比如,保存文件時指定的編碼爲ANSI,python腳本頂部指定的編碼爲#coding:utf-8:

#coding:utf-8

import sys

print sys.getdefaultencoding()

x= "上".decode("utf-8")
y = u"下"
print(x)
print(y)
print(type(y))

 

在cmd中運行此python,報SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xcf in position 0: invalid continuation byte。

 

相反,保存文件時指定的編碼爲utf-8,python腳本頂部指定的編碼爲#coding:gbk:

 

#coding:gbk

import sys

print sys.getdefaultencoding()

x= "上".decode("utf-8")
y = u"下"
print(x)
print(y)
print(type(y))

在cmd中運行此python,報SyntaxError: 'gbk' codec can't decode bytes in position 6-7: illegal multibyte sequence。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章