1. 程式人生 > >【python測試開發棧】帶你徹底搞明白python3編碼原理

【python測試開發棧】帶你徹底搞明白python3編碼原理

在之前的文章中,我們介紹過編碼格式的發展史:[文章傳送門-todo]。今天我們通過幾個例子,來徹底搞清楚python3中的編碼格式原理,這樣你之後寫python指令碼時碰到編碼問題,才能有章可循。

我們先搞清楚幾個概念:

  • 系統預設編碼:指python直譯器預設的編碼格式,在python檔案頭部沒有宣告其他編碼格式時,python3預設的編碼格式是utf-8。
  • 本地預設編碼:作業系統預設的編碼,常見的Windows的預設編碼是gbk,Linux的預設編碼是UTF-8。
  • python檔案頭部宣告編碼格式:修改的是檔案的預設編碼格式,只是會影響python直譯器讀取python檔案時的編碼格式,並不會改變系統預設編碼和本地預設編碼。

通過python自帶的庫,可以檢視系統預設編碼和本地預設編碼

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
>>> import locale
>>> locale.getdefaultlocale()
('zh_CN', 'cp936')
>>>

注意,因為我在windows系統的電腦上 進行測試,所以系統預設編碼返回“cp936”, 這是內碼表(是字元編碼集的別名),而936對應的就是gbk。如果你在linux或者mac上執行上面的程式碼,應該會返回utf-8編碼。

其實總結來看,容易出現亂碼的場景,基本都與讀寫程式有關,比如:讀取/寫入某個檔案,或者從網路流中讀取資料等,因為這個過程中涉及到了編碼 和解碼的過程,只要編碼和解碼的編碼格式對應不上,就容易出現亂碼。下面我們舉兩個具體的例子,來驗證下python的編碼原理,幫助你理解這個過程。注意:下面的例子都是在pycharm中寫的。

01預設的編碼格式

我們新建一個encode_demo.py的檔案,其檔案預設的編碼格式是UTF-8(可以從pycharm右下角看到編碼格式),程式碼如下:

"""
    @author: asus
    @time: 2019/11/21
    @function: 驗證編碼格式
"""
import sys, locale


def write_str_default_encode():
    s = "我是一個str"
    print(s)
    print(type(s))
    print(sys.getdefaultencoding())
    print(locale.getdefaultlocale())

    with open("utf_file", "w", encoding="utf-8") as f:
        f.write(s)
    with open("gbk_file", "w", encoding="gbk") as f:
        f.write(s)
    with open("jis_file", "w", encoding="shift-jis") as f:
        f.write(s)


if __name__ == '__main__':
    write_str_default_encode()

我們先來猜測下結果,因為我們沒有宣告編碼格式,所以python直譯器預設用UTF-8去解碼檔案,因為檔案預設編碼格式就是UTF-8,所以字串s可以正常列印。同時以UTF-8編碼格式寫檔案不會出現亂碼,而以gbk和shift-jis(日文編碼)寫檔案會出現亂碼(這裡說明一點,我是用pycharm直接開啟生成的檔案檢視的,編輯器預設編碼是UTF-8,如果在windows上用記事本開啟則其預設編碼跟隨系統是GBK,gbk_file和utf_file均不會出現亂碼,只有jis_file是亂碼),我們執行看下結果:

# 執行結果
我是一個str
<class 'str'>
utf-8
('zh_CN', 'cp936')

# 寫檔案utf_file、gbk_file、jis_file檔案內容分別是:
我是一個str
����һ��str
�䐥�꘢str

和我們猜測的結果一致,下面我們做個改變,在檔案頭部宣告個編碼格式,再來看看效果。

02 python標頭檔案宣告編碼格式

因為上面檔案encode_demo.py的格式是UTF-8,那麼我們就將其變為gbk編碼。同樣的我們先來推測下結果,在pycharm中,在python檔案頭部宣告編碼為gbk後(頭部加上 # coding=gbk ),檔案的編碼格式變成gbk,同時python直譯器會用gbk去解碼encode_demo.py檔案,所以執行結果應該和用UTF-8編碼時一樣。執行結果如下:

# 執行結果
我是一個str
<class 'str'>
utf-8
('zh_CN', 'cp936')

# 寫檔案utf_file、gbk_file、jis_file檔案內容分別是:
我是一個str
����һ��str
�䐥�꘢str

結果確實是一樣的,證明我們推論是正確的。接下來我們再做個嘗試,假如我們將(# coding=gbk)去掉(需要注意,在pycharm中將 # coding=gbk去掉,並不會改變檔案的編碼格式,也就是說encode_demo.py還是gbk編碼),我們再執行一次看結果:

  File "D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py", line 4
SyntaxError: Non-UTF-8 code starting with '\xd1' in file D:/codespace/python/pythonObject/pythonSample/basic/encodeDemo/encode_demo.py on line 5, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

執行直接報錯了,我們加個斷點,看看具體的異常資訊:

看錯誤提示是UnicodeDecodeError,python直譯器在對encode_demo.py檔案解碼時,使用預設的UTF-8編碼,但是檔案本身是gbk編碼,所以當碰到有中文沒辦法識別時,就丟擲DecodeError。

03 敲黑板,劃重點

python3中的str和bytes

python3的重要特性之一就是對字串和二進位制流做了嚴格的區分,我們宣告的字串都是str型別,不過Str和bytes是可以相互轉換的:

def str_transfor_bytes():
    s = '我是一個測試Str'
    print(type(s))
    # str 轉bytes
    b = s.encode()
    print(b)
    print(type(b))
    # bytes轉str
    c = b.decode('utf-8')
    print(c)
    print(type(c))


if __name__ == '__main__':
    str_transfor_bytes()

需要注意一點:在呼叫encode()和decode()方法時,如果不傳引數,則會使用python直譯器預設的編碼格式UTF-8(如果不在python標頭檔案宣告編碼格式)。但是如果傳參的話,encode和decode使用的編碼格式要能對應上。

python3預設編碼是UTF-8?還是Unicode?

經常在很多文章裡看到,python3的預設編碼格式是Unicode,但是我在本文中卻一直在說python3的預設編碼格式是UTF-8,那麼哪種說法是正確的呢?其實兩種說法都對,主要得搞清楚Unicode和UTF-8的區別(之前文章有提到):

  • Unicode是一個字符集,說白了就是把各種編碼的對映關係全都整合起來,不過它是不可變長的,全部都以兩個位元組或四個位元組來表示,佔用的記憶體空間比較大。
  • UTF-8是Unicode的一種實現方式,主要對 Unicode 碼的資料進行轉換,方便儲存和網路傳輸 。它是可變長編碼,比如對於英文字母,它使用一個位元組就可以表示。

在python3記憶體中使用的字串全都是Unicode碼,當python直譯器解析python檔案時,預設使用UTF-8編碼。

open()方法預設使用本地編碼

在上面的例子中,我們往磁碟寫入檔案時,都指定了編碼格式。如果不指定編碼格式,那麼預設將使用作業系統本地預設的編碼格式,比如:Linux預設是UTF-8,windows預設是GBK。其實這也好理解,因為和磁碟互動,肯定要考慮作業系統的編碼格式。這有區別於encode()和decode()使用的是python直譯器的預設編碼格式,千萬別搞混淆了。

總結

不知道你看完上面的例子後,是否已經徹底理解了python3的編碼原理。不過所有的編碼問題,都逃不過“編碼”和“解碼”兩個過程,當你碰到編碼問題時,先確定原始檔使用的編碼,再確定目標檔案需要的編碼格式,只要能匹配,一般就可以解決編碼的問題。

相關推薦

python測試開發徹底明白python3編碼原理

在之前的文章中,我們介紹過編碼格式的發展史:[文章傳送門-todo]。今天我們通過幾個例子,來徹底搞清楚python3中的編碼格式原理,這樣你之後寫python指令碼時碰到編碼問題,才能有章可循。 我們先搞清楚幾個概念: 系統預設編碼:指python直譯器預設的編碼格式,在python檔案頭部沒有宣告其他編

python測試開發—幫總結Python os模組高頻使用的方法

Python中的os模組是主要和系統操作相關的模組,在平時的工作中會經常用到,花時間整理了os模組的高頻使用方法,同時整理出使用時需要注意的點。歸納來講,os模組的方法可以分為:目錄操作、檔案操作、路徑操作、系統操作等四大類,我們接下來依次進行介紹。 目錄操作相關 建立、刪除、重新命名目錄 # 當前目

python測試開發python基礎語法大盤點

周邊很多同學在用python,但是偶爾會發現有人對python的基礎語法還不是特別瞭解,所以幫大家梳理了python的基礎語法(文中的介紹以python3為例)。如果你已然是python大牛,可以跳過這篇文章。 編碼 python3的預設編碼格式是:UTF-8 ,換句話說也就是:如果不在檔案頭部宣告編碼格式,

python測試開發python記憶體管理機制(一)—引用計數

什麼是記憶體 在開始進入正題之前,我們先來回憶下,計算機基礎原理的知識,為什麼需要記憶體。我們都知道計算機的CPU相當於人類的大腦,其運算速度非常的快,而我們平時寫的資料,比如:文件、程式碼等都是儲存在磁碟上的。磁碟的存取速度完全不能匹配cpu的運算速度,因此就需要一箇中間層來適配兩者的不對等,記憶體由此而來

python測試開發python記憶體管理機制(二)—垃圾回收

在上一篇文章中(python 記憶體管理機制—引用計數)中,我們介紹了python記憶體管理機制中的引用計數,python正是通過它來有效的管理記憶體。今天來介紹python的垃圾回收,其主要策略是引用計數為主,標記-清除和分代回收為輔助的策略(熟悉java的同學回回憶下,其實這和JVM的策略是有類似之處的)

python測試開發—理解python深拷貝與淺拷貝的區別

記憶體的淺拷貝和深拷貝是面試時經常被問到的問題,如果不能理解其本質原理,有可能會答非所問,給面試官留下不好的印象。另外,理解淺拷貝和深拷貝的原理,還可以幫助我們理解Python記憶體機制。這篇文章將會通過一些例子,來驗證記憶體拷貝的過程,幫助大家理解記憶體拷貝的原理。 Python3中的資料型別 我們首先得知

學習python 測試開發

ror 獲得 inf img get detail gpo pex 如果 https://ke.qq.com/course/263945#tuin=107a3c8a https://testerhome.com/topics/11327 python版本:2.7.* 第一節

LightningChart 體數據領略體數據渲染的前世今生

常用 可視化分析 表格 行高 討論 一場 復雜計算 從數據 線圖 前言 3D數據采集領域的高速發展,在具有交互式幀率的現代化工作站上執行高級可視化,體數據的重要性將越來越重要。體數據集可以通過MRI,CT,PET,USCT或回聲定位等技術捕獲,也可以通過物理模擬(流體動力

cggwz的資訊飛船領略計算機世界的美妙和神奇

博主要去備戰高考了!很遺憾不能和大家交流了,但是,請各位不要離開,明年高考結束,我就會強勢迴歸!! 畢竟這是個表白牆 我永遠喜歡chq  ——lovechq 我永遠喜歡御阪美琴 ——cgg 這個隊形由我打破女神大人,我愛你! —

全方位徹底懂Android記憶體洩露

1Java記憶體回收方式 Java判斷物件是否可以回收使用的而是可達性分析演算法。 在主流的商用程式語言中(Java和C#),都是使用可達性分析演算法判斷物件是否存活的。

面試都在問的「微服務」「RPC」「服務治理」「下一代微服務」一文徹底懂!

❝ 文章每週持續更新,各位的「三連」是對我最大的肯定。可以微信搜尋公眾號「 後端技術學堂 」第一時間閱讀(一般比部落格早更新一到兩篇) ❞ 單體式應用程式 與微服務相對的另一個概念是傳統的「單體式應用程式」( Monolithic application ),單體式應用內部包含了所有需要的服務。而且各個服務功

轉載吃透RTMP

描述 也不會 一點 bool event let har 承擔 開發 RTMP協議是Real Time Message Protocol(實時信息傳輸協議)的縮寫,它是由Adobe公司提出的一種應用層的協議,用來解決多媒體數據傳輸流的多路復用(Multiplexing)和分

工程師開發 ,node開發人臉識別門禁系統

fun 兼容 src 是否 images 部分 scrip 部署 htm 效果圖: 知識點: 人臉識別SKD部署, webRTC視頻流處理,URL構建blob對象,Canvas映射截圖,ajax數據交互,Node圖像處理,跨域與

Python web 開發social_django 整合第三方登入

 1、背景: 我們之前寫的一些介面僅僅是知道微博授權的一個流程,要把第三方授權登入的使用者的user_id  弄到我們的user_profile 中來才是 符合業務的需求的 因此gitbub上已經有一些開源的第三方外掛使用 social_app_django   &nbs

Python web 開發django 從請求到響應經歷了什麼?

  setting中註冊的middleware會將使用者request的資料經過這些middlware中有process_request方法和process_response方法註冊進入。 當用戶的request進入view之前會將這些process_request通通呼叫一遍

python web開發viewsets 配置認證類

我們在setting 裡面配置認證類 是一個全域性的,這個auth 類會對token 進行驗證,如果驗證失敗了會丟擲上面原始碼中的異常 但是有的介面,比如獲取首頁,商品列表頁 是不需要使用者 token的,因此這種全域性的配置是不行的,後端的解決方案: 將 token 認證拿到 view 中來做 以

Python web 開發Vue 和 jason web token 除錯

檢視前端Vue 原始碼 登入的request url 是這樣的   我們後端是這樣的   這樣請求的url 不統一,作為後端我們就要改 請求的url ,一般登入都是用的login    login Vue 檢視登入的邏輯 登入成功後,我們

Python web 開發自定義使用者認證函式

自定義 使用者認證類,記得之前在mxonline 裡面做過, 主要思路是:  第一步:在seeting 裡面設定自定義的backends    第二步:在user views 裡面寫檢視函式 自定義使用者認證函式要繼承ModelBackend,並且要重寫

c語言真正走進指標的世界——陣列與指標的關係(一)

       每天下課之後,都感覺老師上課在神仙程式設計,我們一群凡人在底下面無表情地走神,前一秒還是在講加減乘除的基本用法,後一秒就變成了指標陣列、陣列指標、結構體指標和N級指標的性質以及運用............(真是令人頭禿 —^—) ——————

c語言真正走進指標的世界——那些一不小心就會出現的BUG

                                    Let's     &nbs