1. 程式人生 > >聊一聊 Python 2 中的編碼

聊一聊 Python 2 中的編碼

在 Python 尤其是 Python2 中,編碼問題是困擾開發者尤其初學者的一大問題。什麼 Unicode/UTF-8/str ,又是 decode/encode 的,搞得人頭都大了。其實不然,這有點類似 Java 中 java.io 包一樣,看似龐大難懂,但是可以非常精細地定製需求。

螢幕快照 2016-03-01 16.30.04.png

編碼

計算機只可以儲存和處理二進位制資料,所以從文字到計算機可以識別的二進位制之間需要一道對應關係。於是便有了ASCII(American Standard Code for Information Interchange,美國標準資訊交換程式碼),ASCII使用7位二進位制數標記了128(2**7)字元(符號、字母、控制符等),由於1byte=8bit,所以乾脆最高位補個0,湊夠8位以方便計算和處理。

接著,拉丁語系的技術宅們發現,這128個字元的高位空著的,那麼幹脆用來表示拉丁語系的主要符號吧,還是使用單位元組,但是可以表示的字元數量增加了一倍。這套編碼叫做latin-1(iso-8859-1)。

這些宅男們沒有想到,區區一個位元組256個符號,對於東亞國家來講,簡直呵呵了。拿中文為例,僅常用字元就幾千個,於是中國國家標準總局制定了一套中文編碼——GB2312。GB2312通過兩個位元組表示一個漢字,且最高位為0的部分相容ASCII,最高位為1的部分則通過連續的兩個位元組表示一箇中文字。後來又出現了相容GB2312的GBK編碼。

到這裡,依然面臨了一個問題:GB2312或者GBK編碼中,僅可以表示漢字和英文字元,無法做到多語言文字同時表示。這時候,Unicode(又稱萬國碼)出現了。Unicode採用32位二進位制(4位元組)表示一個字元,這樣便可以一套編碼對應多種不同語言。Unicode是一種編碼,它的作用是指定字元到二進位制數之間的對應關係。但是對於儲存和傳輸,Unicode有幾種不同的實現,比較常用的是UTF-8、UTF-16、UTF-32。UTF-32中,每個字元固定佔4位元組,按照Unicode編碼完全對映。而UTF-8和UTF-16則屬於變長編碼,分別使用最少1個(UTF-8)或2個(UTF-16)位元組到最多4個位元組來編碼。

Python原始碼的編碼

Python2中,如果在原始碼首行(或在指定sha-bang時的第二行)不顯式指定編碼,則無法在原始碼中出現非ASCII字元。這是由於Python直譯器預設將原始碼認作ASCII編碼格式。PEP263(點選這裡檢視)中約定,可以通過如下方式之一來宣告原始碼的編碼格式:

Python
1234567 # coding=<coding name># or# -*- coding: <encoding name> -*-# or# vim: set fileencoding=<encoding name> :

Python中的編碼

Python中有兩個常用的由basestring派生出來的表示字串的型別:str,unicode。其中,str類似於C中的字元陣列或者Java中的byte陣列,事實上你可以將它理解為一個儲存二進位制內容的容器,str不儲存編碼資訊,如果對str型別的字串迭代的話,則會按照其在記憶體中的位元組序依次迭代,意味著如果這個字串儲存的是多位元組字元(Unicode/GBK等),則會截斷這個字元,演示如下:

螢幕快照 2016-03-01 16.15.08.png

而對於unicode型別,Python在記憶體中儲存和使用的時候是按照UTF-8格式,在程式碼中的表示為字串前加u,如:

螢幕快照 2016-03-01 16.23.18.png

unicodestr之間的轉換,則用到了encodedeocde方法。decode表示將一個(str)字串按照給定的編碼解析為unicode型別,encode則表示將一個unicode字串按照指定編碼解析為位元組陣列(str):

螢幕快照 2016-03-01 16.26.11.png

螢幕快照 2016-03-01 16.30.04.png

檔案讀寫

內建的open函式開啟檔案時,read方法讀取的是一個str(私以為叫做位元組陣列更合適),如果讀取的是其它編碼的文字,則需要decode之後再做使用。

螢幕快照 2016-03-01 16.54.33.png

對於使用open函式開啟檔案之後的寫操作(多位元組編碼的字串),則需要將需要寫入的字串按照其編碼encode為一個str,如果直接寫入,則會引發如下錯誤(如果在程式碼中加入了encoding宣告,則會按照宣告的編碼格式encode後寫入):

螢幕快照 2016-03-01 16.56.06.png

除此以外,codecs模組也提供了一個open函式,可以直接指定好編碼開啟一個文字檔案,那麼讀取到的檔案內容則直接是一個unicode字串。對應的指定編碼後的寫入檔案,則可以直接將unicode寫到檔案中。通過codecs.open可以避免很多編碼問題:

螢幕快照 2016-03-01 17.02.53.png

建議

對於Python程式碼中避免遇到編碼問題,有一些小建議:

  • 字元編碼宣告:在程式碼開頭宣告編碼格式
  • 使用codecs的open函式處理文字檔案
  • 儘可能使用unicode而不是str:在所有字串的引號前加u

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

相關推薦

Python 2 編碼

在 Python 尤其是 Python2 中,編碼問題是困擾開發者尤其初學者的一大問題。什麼 Unicode/UTF-8/str ,又是 decode/encode 的,搞得人頭都大了。其實不然,這有點類似 Java 中 java.io 包一樣,看似龐大難懂,但是可以非常精細地

給大家雲收藏從 Spring Boot 1.0 升級到 2.0 所踩的坑

springboot 雲收藏 先給大家曬一下雲收藏的幾個數據,作為一個 Spring Boot 的開源項目(https://github.com/cloudfavorites/favorites-web)目前在 Github 上面已經有1600多個 Star,如果按照 SpringBoot 標簽進行篩

深度學習常用的激勵函式

   大家都知道,人腦的基本計算單元叫做神經元。現代生物學表明,人的神經系統中大概有860億神經元,而這數量巨大的神經元之間大約是通過1014−1015個突觸連線起來的。上面這一幅示意圖,粗略地描繪了一下人體神經元與我們簡化過後的數學模型。每個神經元都從樹突接受訊號,同時順著某個軸突傳遞

嵌入式常用的實時作業系統(RTOS)

嵌入式Linux系統 VS RTOS 一提到嵌入式的作業系統,自然繞不開嵌入式Linux作業系統。嵌入式linux 是將日益流行的Linux作業系統進行裁剪修改,使之能在嵌入式計算機系統上執行。它效能優異,軟體移植容易,程式碼開放,有許多應用軟體支援,應用產品開發週期短,新

Android 巧妙的位操作

前言 我們之前,在計算機當中,它是以二進位制的形式來進行數的儲存和加減乘除的。 講解之前,我們先來了解一下基本的位操作 位操作 含義 具體含義 & 表示與

【番外篇】深度學習的資料增強與實現

深度學習的訓練往往需要海量的資料,而如今資料又是如此的寶貴(如醫學影象),因此如何利用有效的資料獲得更好的效果呢?資料增強(data augmentation)就是一種常用的方法。 工欲善其事必先利其器。 先來看下實現本文資料增強所需要的必要環境: python3.5

資料倉庫的元資料管理系統

原文地址 一、元資料的定義 按照傳統的定義,元資料(Metadata)是關於資料的資料。在資料倉庫系統中,元資料可以幫助資料倉庫管理員和資料倉庫的開發人員非常方便地找到他們所關心的資料;元資料是描述資料倉庫內資料的結構和建立方法的資料,可將其按用途的不同分為兩類:

Javadouble精度去哪了

前段時間, 因為要測試一個剛出爐的高頻策略, 放實盤去跑吧, 怕出岔, 所以寫了個簡單的回測系統, 跑一遍歷史資料. 其中有一部分是關於撮合系統, 簡陋了點, 還算能跑得起來, 幾個用例下來, 也沒什麼問題, 接著增加歷史資料量, 居然出現了負數, 簡直不可能發生的事情居然出現了, 雖然都是小金額的偏差,

JQdelegate事件委託的好處

下面舉個例子 我們希望通過點選使得點選的li標籤變紅 HTML <body style="height:2000px;"> <ul> <li>1111&

從nginx熱更新Golang的伺服器熱更新(上)

從nginx熱更新聊一聊Golang中的熱更新(上) 靜態語言在伺服器程式設計時都會遇到這樣的問題:如何保證已有的連線服務不中斷同時又升級版本? 最近花了點時間看了下nginx熱更新程式碼流程,想了下結合之前的經驗一併總結下熱更新 熱更新是什麼? 舉個例子,

資料庫的鎖

背景 資料庫中有一張叫後宮佳麗的表,每天都有幾百萬新的小姐姐插到表中,光陰荏苒,夜以繼日,日久生情,時間長了,表中就有了幾十億的小姐姐資料,看到幾十億的小姐姐,每到晚上,我可愁死了,這麼多小姐姐,我翻張牌呢? 辦法當然是精兵簡政,刪除那些age>18的,給年輕的小姐姐們留位置... 於是我在資料庫中添加

Java的各種運算子

計算機之所以叫“計算機”,其最基本用途之一就是運算,對應剛剛接觸Java的小夥伴而言,熟悉並掌握Java中的各種運算子及其在表示式中的運算優先順序是十分必要的。 算術運算 算術運算主要用來處理數學中的加、減、乘、除四則運算。是最簡單、最常用的運算子。 1. 除與取模:資料做

借 redis cluster 叢集,叢集資料分佈演算法

Redis Cluster 叢集中涉及到了資料分佈問題,因為 redis cluster 是多 master 的結構,每個 master 都是可以提供儲存服務的,這就會涉及到資料分佈的問題,在新的 redis 版本中採用的是虛擬槽分割槽技術來解決資料分佈的問題,關於什麼是虛擬槽分割槽技術我們後面會詳細的介紹。

webpack 的 preloading 和 Prefetching

聊一聊 webpack 中的 preloading 和 Prefetching 提到 Preloading 和 Prefetching 就不得不先說一下程式碼分割,通過下面的例子我們來說明為什麼需要程式碼分割? // index.js import _ from 'lodash'; // 假設大小為 1 MB

MySQL 的事務及其實現原理

說到資料庫,那就一定會聊到事務,事務也是面試中常問的問題,我們先來一個面試場景: 面試官:"事務的四大特性是什麼?" 我:"ACID,即原子性(Atomicity)、隔離性(Isolation)、永續性(Durability)、一致性(Consistency)!" 面試官:"在 MySQL 資料庫的 Inno

簡單JS的迴圈引用及問題

本文主要從 JS 中為什麼會出現迴圈引用,垃圾回收策略中引用計數為什麼有很大的問題,以及迴圈引用時的物件在使用 JSON.stringify 時為什麼會報錯,怎樣解決這個問題簡單談談自己的一些理解。 1. 什麼是迴圈引用 當物件 1 中的某個屬性指向物件 2,物件 2 中的某個屬性指向物件 1 就會出現迴圈引

InnoDB 引擎的索引型別

索引對資料庫有多重要,我想大家都已經知道了吧,關於索引可能大家會對它多少有一些誤解,首先索引是一種資料結構,並且索引不是越多越好。合理的索引可以提高儲存引擎對資料的查詢效率。 形象一點來說呢,索引跟書本的目錄一樣,能否快速的查詢到你需要的資訊,取決於你設計的目錄是否合理。 MySQL 資料庫有很多種索引,每種

InnoDB 引擎的這些索引策略

在上一篇中,我們簡單的介紹了一下 InnoDB 引擎的索引型別,這一篇我們繼續學習 InnoDB 的索引,聊一聊索引策略,更好的利用好索引,提升資料庫的效能,主要聊一聊覆蓋索引、最左字首原則、索引下推。 覆蓋索引 覆蓋索引是指在普通索引樹中可以得到查詢的結果,不需要在回到主鍵索引樹中再次搜尋。 建立如下這張表

MySQL 的資料編輯過程涉及的兩階段提交

MySQL 資料庫中的兩階段提交,不知道您知道不?這篇文章就簡單的聊一聊 MySQL 資料庫中的兩階段提交,兩階段提交發生在資料變更期間(更新、刪除、新增等),兩階段提交過程中涉及到了 MySQL 資料庫中的兩個日誌系統:redo 日誌和 binlog 檔案。 redo 日誌前面已經介紹過了,就不再介紹了,簡

React虛擬DOM

### 1. 什麼是虛擬 DOM 在 React 中實際上是 render 函式中return 的內容會生成 DOM,return 中的內容由兩部分組成,一部分是 JSX ,另一部分就是 state 中的資料,所以簡單來講,在 React 中 JSX 結合 state 就生成了 DOM。 現在拋開虛擬 D