之前遇到此異常UnicodeEncodeError: 'ascii' codec can't encode characters...,都是用這種方式解決:sys.setdefaultencoding('utf-8')
今天看到如下文章,闡述了此方式的弊端:
http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
但此文章只考慮了未使用第三方庫的情況下的解決辦法,而第三方庫里如果也有print的話,就束手無策了,總不能把第三方的所有print都加上encode吧。
另外此文中說的修改編碼為utf8的隱患,其實都是因為沒有使用unicode字符串或兩種字符串混用而已,如果項目中規定只可使用u'unicode字符串',上述隱患即可基本避免。歸根結底最大的風險就是第三方庫的不可控,print編碼和unicode字符串都不可控,所以不能使用setdefaultencoding。
我這次是在用Java啟動python時,print中文,就會報ascii的異常,我發現此種情況下sys.stdout.encoding其實為None,而Ubuntu中普通命令行時此變量則是UTF-8。
那如何修改sys.stdout.encoding呢?(直接修改會報錯TypeError: readonly attribute)
所以最終找到http://www.macfreek.nl/memory/Encoding_of_Python_stdout
python2修改方式(python3略不同,原文中也有寫)
1 if sys.stdout.encoding != 'UTF-8': 2 sys.stdout = codecs.getwriter('utf-8')(sys.stdout, 'strict') 3 if sys.stderr.encoding != 'UTF-8': 4 sys.stderr = codecs.getwriter('utf-8')(sys.stderr, 'strict')
這樣就完美解決輸出中文時的ascii編碼異常了,而且也不用重新設置sys的默認編碼。
后記:
理想很豐滿,現實很骨感,有的時候還是要用setdefaultencoding的。。。
比如不僅是print,還涉及到遍歷文件,並且要寫結果文件時,在shell下運行正常,可能用java啟動的python就會報編碼問題,如果不改java那邊,可能就要選擇setdefaultencoding了,因為如果兼容了java,可能shell下又會報編碼問題了,按下葫蘆浮起瓢。當然如果把相關幾個涉及編碼的地方包個函數,在里面根據情況來切換也行,如果時間允許也可以考慮。