標籤:證明 不能 python3 test 特性 toolbar default 額外 pre
https://www.cnblogs.com/zihe/p/6993891.html一 瞭解字元編碼的知識儲備
1. 文字編輯器存取檔案的原理(nodepad++,pycharm,word)
開啟編輯器就開啟了啟動了一個進程,是在記憶體中的,所以在編輯器編寫的內容也都是存放與記憶體中的,斷電後資料丟失
因而需要儲存到硬碟上,點擊儲存按鈕,就從記憶體中把資料刷到了硬碟上。
在這一點上,我們編寫一個py檔案(沒有執行),跟編寫其他檔案沒有任何區別,都只是在編寫一堆字元而已。
2. python解譯器執行py檔案的原理 ,例如python test.py
第一階段:python解譯器啟動,此時就相當於啟動了一個文字編輯器
第二階段:python解譯器相當於文字編輯器,去開啟test.py檔案,從硬碟上將test.py的檔案內容讀入到記憶體中
第三階段:python解譯器解釋執行剛剛載入到記憶體中test.py的代碼
總結:
- python解譯器是解釋執行檔案內容的,因而python解譯器具備讀py檔案的功能,這一點與文字編輯器一樣
- 與文字編輯器不一樣的地方在於,python解譯器不僅可以讀檔案內容,還可以執行檔案內容
二 什麼是字元編碼
電腦要想工作必須通電,也就是說‘電’驅使電腦幹活,而‘電’的特性,就是高低電平(高低平即位元1,低電平即位元0),也就是說電腦只認識數字
編程的目的是讓電腦幹活,而編程的結果說白了只是一堆字元,也就是說我們編程最終要實現的是:一堆字元驅動電腦幹活
所以必須經過一個過程:
字元--------(翻譯過程)------->數字
這個過程實際就是一個字元如何對應一個特定數位標準,這個標準稱之為字元編碼
三 字元編碼的發展史
階段一:現代電腦起源於美國,最早誕生也是基於英文考慮的ASCII
ASCII:一個Bytes代表一個字元(英文字元/鍵盤上的所有其他字元),1Bytes=8bit,8bit可以表示0-2**8-1種變化,即可以表示256個字元
ASCII最初只用了後七位,127個數字,已經完全能夠代表鍵盤上所有的字元了(英文字元/鍵盤的所有其他字元)
後來為了將拉丁文也編碼進了ASCII表,將最高位也佔用了
階段二:為了滿足中文,中國人定製了GBK
GBK:2Bytes代表一個字元
為了滿足其他國家,各個國家紛紛定製了自己的編碼
日本把日文編到Shift_JIS
裡,韓國把韓文編到Euc-kr
裡
階段三:各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文本中,顯示出來會有亂碼。
於是產生了unicode, 統一用2Bytes代表一個字元, 2**16-1=65535,可代表6萬多個字元,因而相容萬國語言
但對於通篇都是英文的文本來說,這種編碼方式無疑是多了一倍的儲存空間(二進位最終都是以電或者磁的方式儲存到儲存介質中的)
於是產生了UTF-8,對英文字元只用1Bytes表示,對中文字元用3Bytes
需要強調的一點是:
unicode:簡單粗暴,所有字元都是2Bytes,優點是字元->數位轉換速度快,缺點是佔用空間大
utf-8:精準,對不同的字元用不同的長度表示,優點是節省空間的,缺點是:字元->數位轉換速度慢,因為每次都需要計算出字元需要多長的Bytes才能夠準確表示
- 記憶體中使用的編碼是unicode,用空間換時間(程式都需要載入到記憶體才能運行,因而記憶體應該是儘可能的保證快)
- 硬碟中或者網路傳輸用utf-8,網路I/O延遲或磁碟I/O延遲要遠大與utf-8的轉換延遲,而且I/O應該是儘可能地節省頻寬,保證資料轉送的穩定性。
四.字元編碼分類
電腦由美國人發明,最早的字元編碼為ASCII,只規定了英文字母數字和一些特殊字元與數位對應關係。
ascii用1個位元組(8位二進位)代表一個字元
unicode常用2個位元組(16位二進位)代表一個字元,生僻字需要用4個位元組
如果我們的文檔通篇都是英文,你用unicode會比ascii耗費多一倍的空間,在儲存和傳輸上十分的低效
本著節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8
編碼。UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文本包含大量英文字元,用UTF-8編碼就能節省空間的:
字元 |
ASCII |
Unicode |
UTF-8 |
A |
01000001 |
00000000 01000001 |
01000001 |
中 |
x |
01001110 00101101 |
11100100 10111000 10101101 |
從上面的表格還可以發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以,大量只支援ASCII編碼的曆史遺留軟體可以在UTF-8編碼下繼續工作。
五 字元編碼的使用5.1 文字編輯器一鍋端
5.1.2 文字編輯器nodpad++
總結:
無論是何種編輯器,要防止檔案出現亂碼(請一定注意,存放一段代碼的檔案也僅僅只是一個普通檔案而已,此處指的是檔案沒有執行前,我們開啟檔案時出現的亂碼)
核心法則就是,檔案以什麼編碼儲存的,就以什麼編碼方式開啟
而檔案編碼儲存時候使用的編碼方式是右下角的編碼方式,而解碼的時候是使用文檔開頭申明的編碼方式,兩種編碼不同的時候很容易出現亂碼的情況。
5.2 程式的執行
python test.py (我再強調一遍,執行test.py的第一步,一定是先將檔案內容讀入到記憶體中)
階段一:啟動python解譯器
階段二:python解譯器此時就是一個文字編輯器,負責開啟檔案test.py,即從硬碟中讀取test.py的內容到記憶體中
此時,python解譯器會讀取test.py的第一行內容,#coding:utf-8,來決定以什麼編碼格式來讀入記憶體,這一行就是來設定python解譯器這個軟體的編碼使用的編碼格式這個編碼,
可以用sys.getdefaultencoding()查看,如果不在python檔案指定頭資訊#-*-coding:utf-8-*-,那就使用預設的
python2中預設使用ascii,python3中預設使用utf-8
階段三:讀取已經載入到記憶體的代碼(unicode編碼的二進位),然後執行,執行過程中可能會開闢新的記憶體空間,比如x="egon"
記憶體的編碼使用unicode,不代表記憶體中全都是unicode編碼的二進位,
在程式執行之前,記憶體中確實都是unicode編碼的二進位,比如從檔案中讀取了一行x="egon",其中的x,等號,引號,地位都一樣,都是一般字元而已,都是以unicode編碼的二進位形式存放與記憶體中的
但是程式在執行過程中,會申請記憶體(與程式碼所存在的記憶體是倆個空間),可以存放任意編碼格式的資料,比如x="egon",會被python解譯器識別為字串,會申請記憶體空間來存放"hello",然後讓x指向該記憶體位址,此時新申請的該記憶體位址儲存也是unicode編碼的egon,如果代碼換成x="egon".encode(‘utf-8‘),那麼新申請的記憶體空間裡存放的就是utf-8編碼的字串egon了
針對python3如
瀏覽網頁的時候,伺服器會把動態產生的Unicode內容轉換為UTF-8再傳輸到瀏覽器
如果服務端encode的編碼格式是utf-8, 用戶端記憶體中收到的也是utf-8編碼的二進位。
5.3 python2與python3的區別 5.3.1 在python2中有兩種字串類型str和unicode
str類型
當python解譯器執行到產生字串的代碼時(例如s=‘林‘),會申請新的記憶體位址,然後將‘林‘encode成檔案開頭指定的編碼格式,這已經是encode之後的結果了,所以s只能decode
1 #_*_coding:gbk_*_2 #!/usr/bin/env python3 4 x=‘林‘5 # print x.encode(‘gbk‘) #報錯6 print x.decode(‘gbk‘) #結果:林
所以很重要的一點是:
在python2中,str就是編碼後的結果bytes,str=bytes,所以在python2中,unicode字元編碼的結果是str/bytes
#coding:utf-8s=‘林‘ #在執行時,‘林‘會被以conding:utf-8的形式儲存到新的記憶體空間中print repr(s) #‘\xe6\x9e\x97‘ 三個Bytes,證明確實是utf-8print type(s) #<type ‘str‘>s.decode(‘utf-8‘)# s.encode(‘utf-8‘) #報錯,s為編碼後的結果bytes,所以只能decode
unicode類型
當python解譯器執行到產生字串的代碼時(例如s=u‘林‘),會申請新的記憶體位址,然後將‘林‘以unicode的格式存放到新的記憶體空間中,所以s只能encode,不能decode
s=u‘林‘print repr(s) #u‘\u6797‘print type(s) #<type ‘unicode‘># s.decode(‘utf-8‘) #報錯,s為unicode,所以只能encodes.encode(‘utf-8‘)
列印到終端
對於print需要特別說明的是:
當程式執行時,比如
x=‘林‘
print(x) #這一步是將x指向的那塊新的記憶體空間(非代碼所在的記憶體空間)中的記憶體,列印到終端,而終端仍然是運行於記憶體中的,所以這列印可以理解為從記憶體列印到記憶體,即記憶體->記憶體,unicode->unicode
對於unicode格式的資料來說,無論怎麼列印,都不會亂碼
python3中的字串與python2中的u‘字串‘,都是unicode,所以無論如何列印都不會亂碼
在pycharm中
在windows終端
但是在python2中存在另外一種非unicode的字串,此時,print x,會按照終端的編碼執行x.decode(‘終端編碼‘),變成unicode後,再列印,此時終端編碼若與檔案開頭指定的編碼不一致,亂碼就產生了
在pycharm中(終端編碼為utf-8,檔案編碼為utf-8,不會亂碼)
在windows終端(終端編碼為gbk,檔案編碼為utf-8,亂碼產生)
思考題:
分別驗證在pycharm中和cmd中下述的列印結果
#coding:utf-8s=u‘林‘ #當程式執行時,‘林‘會被以unicode形式儲存新的記憶體空間中#s指向的是unicode,因而可以編碼成任意格式,都不會報encode錯誤s1=s.encode(‘utf-8‘)s2=s.encode(‘gbk‘)print s1 #列印正常否?print s2 #列印正常否print repr(s) #u‘\u6797‘print repr(s1) #‘\xe6\x9e\x97‘ 編碼一個漢字utf-8用3Bytesprint repr(s2) #‘\xc1\xd6‘ 編碼一個漢字gbk用2Bytesprint type(s) #<type ‘unicode‘>print type(s1) #<type ‘str‘>print type(s2) #<type ‘str‘>
5.3.2 在python3中也有兩種字串類型str和bytes
str是unicode
#coding:utf-8s=‘林‘ #當程式執行時,無需加u,‘林‘也會被以unicode形式儲存新的記憶體空間中,#s可以直接encode成任意編碼格式s.encode(‘utf-8‘)s.encode(‘gbk‘)print(type(s)) #<class ‘str‘>
bytes是bytes
#coding:utf-8s=‘林‘ #當程式執行時,無需加u,‘林‘也會被以unicode形式儲存新的記憶體空間中,#s可以直接encode成任意編碼格式s1=s.encode(‘utf-8‘)s2=s.encode(‘gbk‘)print(s) #林print(s1) #b‘\xe6\x9e\x97‘ 在python3中,是什麼就列印什麼print(s2) #b‘\xc1\xd6‘ 同上print(type(s)) #<class ‘str‘>print(type(s1)) #<class ‘bytes‘>print(type(s2)) #<class ‘bytes‘>
Python(字元編碼)