add by zhj: 在Python中有些庫的接口要求參數必須是str類型字符串,有些接口要求參數必須是unicode類型字符串。對於str類型的字符串,調用len()和遍歷時,其實都是以字節爲單位的,這個太坑爹了,同一個字符使用不一樣的編碼格式,長度每每是不一樣的。對unicode類型的字符串調用len()和遍歷纔是以字符爲單位,這是咱們所要的。另外,Django,Django REST framework的接口都是返回unicode類型的字符串。爲了統一,我我的建議使用from __future__ import unicode_literals,將模塊中顯式出現的全部字符串轉爲unicode類型,不過,對於必須使用str字符串的地方要加以注意。關於字符串類型,也是Python2坑爹的地方編碼
在py2.7的項目中用了__future__模塊中的 unicode_literals 來爲兼容py3.x作準備,今天遇到一個UnicodeEncodeError的錯誤,跟了下,發現這個小坑值得注意。是怎麼樣的一個坑呢?跟着代碼看看。順便深究一下原理。url
1. 問題
未引用unicode_literalsspa
#coding:utf-8 from datetime import datetime now = datetime.now() print now.strftime('%m月%d日 %H:%M')
這段代碼正常執行,輸出: 03月12日 21:53code
引入unicode_literalshtm
#coding:utf-8 from __future__ import unicode_literals from datetime import datetime now = datetime.now() print now.strftime('%m月%d日 %H:%M')
拋出以下錯誤:blog
Traceback (most recent call last): File "unicode_error_demo2.py", line 7, in <module> print now.strftime('%m月%d日 %H:%M') UnicodeEncodeError: 'ascii' codec can't encode character u'\u6708' in position 2: ordinal not in range(128)
2. 緣由分析
由於datetime.strftime()只接受str類型的字符串,不接受unicode類型的字符串。接口
3. 解決方案
方案一(推薦):傳入str類型的參數
#coding:utf-8 from __future__ import unicode_literals from datetime import datetime now = datetime.now() print now.strftime('%m月%d日 %H:%M'.encode('utf-8')) # 指明str類型字符串
方案二(不推薦):設置運行時編碼爲utf-8
#coding:utf-8 from __future__ import unicode_literals import sys from datetime import datetime reload(sys) sys.setdefaultencoding('utf-8') now = datetime.now() print now.strftime('%m月%d日 %H:%M')
參考資料:
- 由__future__中unicode_literals引發的錯誤來研究python中的編碼問題
- 黃聰:解決python中文處理亂碼,先要弄懂「字符」和「字節」的差異
- http://docs.python.org/2/library/datetime.html#datetime.date.strftime
- http://docs.python.org/2.7/library/functions.html#getattr
- http://docs.python.org/2/whatsnew/2.6.html?highlight=bytestring#pep-3112-byte-literals
- http://www.cnblogs.com/huxi/articles/1897271.html
- http://stackoverflow.com/questions/6269765/what-does-the-b-character-do-in-front-of-a-string-literal