python學習筆記 --- setdefaultencoding() : reload(sys)後沒法正常執行命令的緣由

寫在前面

一個很難找到問題所在的問題,後來是經過網上的博文才知道了是怎麼樣的緣由,reload(sys)不能隨便用,由於一旦重置了,不少環境變量就不同了。python

正文

搞搞編碼

首先是問題的來源:ubuntu

我在寫python腳本遇到了下面這個問題函數

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

至關不能理解,這其實就涉及了python裏面至關複雜的編碼的問題。在python中運行的字符串都是unicode編碼的,爲何須要這麼一箇中間的編碼,實際上是頗有用的,保證了編碼與編碼之間的互通性。編碼

首先,你們確定知道encode和decode,用法以下code

str = 'dafd'
unicode_str = str.decode('gb2312') #這表示將gb2312編碼的str轉化成unicode
unicode_str.encode('utf-8') #這表示將unicode編碼的unicode_str轉化成utf-8編碼

所以,轉碼的時候必定要先搞明白,字符串str是什麼編碼,而後decode成unicode,而後再encode成其餘編碼utf-8

另外,
代碼中字符串的默認編碼與代碼文件自己的編碼一致。記住!~ci

如:s='中文'

若是是在utf8的文件中,該字符串就是utf8編碼,若是是在gb2312的文件中,
則其編碼爲gb2312。這種狀況下,要進行編碼轉換,
都須要先用decode方法將其轉換成unicode編碼,
再使用encode方法將其轉換成其餘編碼。一般,在沒有指定特定的編碼方式時,都是使用的系統默認編碼建立的代碼文件。 

若是字符串是這樣定義:s=u'中文'

則該字符串的編碼就被指定爲unicode了,即python的內部編碼,
而與代碼文件自己的編碼無關。所以,對於這種狀況作編碼轉換,只須要直接使用encode方法將其轉換成指定編碼便可。

若是一個str已是unicode了,這時候再去decode就會出錯,很好理解。unicode

得到系統的默認編碼字符串

#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()  

該段程序在英文WindowsXP上輸出爲:ascii 
但其實在ubuntu裏也是這樣的問題,這其實就是我寫這篇文章的初衷,由於我被這個問題困擾了好久!

s = '你好'
print s

輸出控制檯的編碼是ascii時,若是你print的是unicode就會出現這個錯誤:terminal

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

只要改爲 print s.encode('utf-8')就ok了。

爲何要reload(sys)

剛剛這麼講好像就解決了?其實不是的,我有個函數tf.train.BytesList,這個函數的參數是一個str,可是這個str的編碼由於系統默認編碼的緣由出錯了,就是上面的錯。這時候的解決辦法通常是reload(sys)。

可是,你會看到卡住了?實際上是輸出看不到了,網上有這樣的解答。

IDLE做爲一個GUI Shell環境,在啓動初始化過程當中,
會設置特定的標準輸入、標準輸出和標準錯誤輸出,使得輸入和輸出都在IDLE的GUI Shell中。
而若是手動執行了reload(sys)之後,sys模塊的這三個變量將會被重置,
致使輸出沒法顯示在IDLE。因此解決方案很簡單,只須要在reload以前把這三個變量都複製一份,reload以後再恢復回來就好了

上面的IDLE其實不僅是IDLE,像我就是在jupyter的狀況下出錯的,terminal下也是同樣。因此要記得補上如下代碼:

stdi,stdo,stde=sys.stdin,sys.stdout,sys.stderr
reload(sys)
sys.stdin,sys.stdout,sys.stderr=stdi,stdo,stde

ok!就寫到這,祝你們coding愉快~

相關文章
相關標籤/搜索