目錄python
Python test.py
(我再強調一遍,執行test.py的第一步,必定是先將文件內容從硬盤讀入到內存中)程序員
test.py文件內容以gbk格式保存的,內容爲:編輯器
此時,Python解釋器會讀取test.py的第一行內容,#coding:utf-8
或#-*-coding:utf-8-*-
,以此決定以什麼編碼格式將代碼讀入內存,這一行就是設定Python解釋器這個軟件使用的編碼格式。編碼
能夠用sys.getdefaultencoding()查看,若是不在Python文件指定頭信息#-*-coding:utf-8-*-
,那就使用Python默認的編碼格式。翻譯
import sys sys.getdefaultencoding()
'utf-8'
Python2中默認使用ascii,Python3中默認使用utf-8。code
改正:在test.py指定文件頭,字符編碼必定要爲gbk。即更正爲blog
#coding:gbk 你好啊
內存的編碼使用Unicode,不表明內存中全都是Unicode,由於在程序執行以前,內存中確實都是Unicode,好比從文件中讀取了一行name="nick",其中的name、等號、引號的地位都同樣,都是普通字符而已,都是以Unicode的格式存放於內存中的。內存
可是程序在執行過程當中,會申請內存(與程序代碼所存在的內存是倆個空間)用來存放Python的數據類型的值,而Python的字符串類型又涉及到了字符的概念。utf-8
好比name="nick",會被Python解釋器識別爲字符串,會申請內存空間來存放字符串類型的值,至於該字符串類型的值被識別成何種編碼存放,這就與Python解釋器的有關了,而Python2與Python3的字符串類型又有所不一樣。ci
在Python2中有兩種字符串類型str和Unicode。
當Python解釋器執行到產生字符串的代碼時(例如x='上'
),會申請新的內存地址,而後將'上'編碼成文件開頭指定的編碼格式
由於直接print()會自動轉換編碼,咱們使用encode()方法查看'上'的字符編碼。
# 3、Python2中代碼 # 4、coding:gbk x = '上' y = '下' print([x, y]) # ['\xc9\xcf', '\xcf\xc2'] # 5、\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)
這樣計算機按照從左往右的順序讀:
也就是說,每一個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。
# 6、Python2中代碼 # 7、coding:gbk x = '上'.decode('gbk') y = '下'.decode('gbk') print([x, y]) # [u'\u4e0a', u'\u4e0b']
當Python解釋器執行到產生字符串的代碼時(例如s=u'林'),會申請新的內存地址,而後將'林'以Unicode的格式存放到新的內存空間中,因此s只能encode,不能decode。
# 8、Python2中代碼 # 9、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,屌不屌?
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編碼能夠和任意的字符編碼相互轉換,並在讀取時按照所需的編碼區讀取,這樣就很好解決了字符編碼的問題