2013-06-11 64 views
1

unicode和字符串編碼仍然讓我頭疼。 I follow this question/answer to can be added special characters(äÄÜ..)to message。Django unicode concatenation

對於下面的結構,我很難理解爲什麼版本2工作,版本1沒有。

我的模型:

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals 

class Project(models.Model): 
    """ 
    Representation of a project 
    """ 

    name = models.CharField(max_length=200) 

    def __unicode__(self): 
      return '%s ' % (self.name) 

版本1:

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals 

def print_project(self, project): 
     project_prefix = "Project: " 
     print (project_prefix + str(project)) 

版本2:

# -*- coding: utf-8 -*- 

def print_project(self, project): 
     project_prefix = "Project: " 
     print (project_prefix + str(project)) 

正如你看到的,唯一的區別是,我做這個from __future__ import unicode_literals進口。拋出的錯誤如下:

'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) 
+1

這應該有用嗎? http://stackoverflow.com/questions/809796/any-gotchas-using-unicode-literals-in-python-2-6 – karthikr

+0

謝謝。絕對有幫助! –

回答

3

__future__語句後,你的文字是不是str對象,但unicode對象。這是聲明的重點。這在__future__文檔或PEP 3112(它們大部分時間都在討論如何編寫Python 2樣式的bytes對象,因爲字符串文字現在是Unicode)時沒有描述得太好。但這就是它的作用。

您可以在交互式解釋測試:

>>> 'abc' 
'abc' 
>>> from __future__ import unicode_literals 
>>> 'abc' 
u'abc' 

所以,在第2版,你把兩個str物體放在一起,這是很容易。但在版本1中,您將添加一個unicodestr。這可以通過使用缺省編碼(ASCII碼)自動將str轉換爲unicode來實現,該編碼不起作用。


解決這個問題的最簡單的方法是讓projectunicode本身:

def print_project(self, project): 
    project_prefix = "Project: " 
    print (project_prefix + unicode(project)) 

這種意志,其實,有無工作__future__語句有了它,project_prefix已經unicode ;沒有它,這是一個str,將從ASCII解碼,但沒關係,因爲它 ASCII。

如果你想使用非ASCII文字(在project_prefix),你想你的代碼與不__future__聲明工作,你將不得不手動解碼:

def print_project(self, project): 
    project_prefix = "Project: ".decode('utf-8') 
    print (project_prefix + unicode(project)) 

(確保。相匹配的源文件的編碼申報,當然)


在一個評論,你問:

使用__future__導入語句時是否還需要在.py文件的開頭定義編碼?# - 編碼:utf-8 -

簡短回答是肯定的。

我不知道這個文檔是否直接覆蓋了這個地方,但如果你仔細想想,就沒有別的辦法可以工作。

爲了將8位源代碼中的文字解釋爲Unicode,Python編譯器必須解碼它們。它知道如何解碼它們的唯一方法就是編碼聲明。

另一種看待這個問題的方式是,__future__聲明使Python 2像Python 3一樣工作,就字符串文字而言,而Python 3需要編碼聲明。

如果您想自己測試,請將以下內容複製爲UTF文件並將其粘貼到文本文件中。 (請注意,您必須使用不理解編碼聲明的編輯器來執行此操作,例如emacs可能會在保存時將您的UTF-8文本轉換爲Latin-1)。

# -*- coding: latin-1 -*- 
from __future__ import unicode_literals 
print repr('é') 

當你運行它,它會打印出u'\xc3\xa9',不u'\xe9'

雖然如果您沒有指定編碼,Python 3默認爲UTF-8,但Python 2.5-2.7默認爲ASCII,即使使用unicode_literals也是如此。所以,你仍然需要編碼聲明。 (即使在3.x中也是如此,即使是在3.x中也是如此,這也使得很多程序員的文本編輯都很開心,所以這可能是一種值得保留的習慣,直到我們深入到未來,沒有人記得Latin-1和Shift- JIS和cp1250等)。

+0

感謝您的完美答案!我已經檢查過它,它工作。我將採用unicode(項目)方法。還有一個問題出現在我的腦海裏。當使用__future__ import語句時,我還需要在.py文件的開頭定義編碼嗎? # - * - 編碼:utf-8 - * - –

+0

@Tom:是的。讓我編輯答案進一步的細節。 – abarnert

+0

非常感謝!通過你的答案瞭解了很多關於編碼的知識。 –