2013-06-11 79 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

非常感谢!通过你的答案了解了很多关于编码的知识。 –