unicode和字符串编码还是让我有些头疼。 我关注了this问题/答案能够向消息添加特殊字符 (äÄÜ..)。
对于以下结构,我很难理解为什么版本 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)
最佳答案
在 __future__
语句之后,您的文字不是 str
对象,而是 unicode
对象。这就是声明的全部要点。 __future__
中对此描述得不太好。文档或 PEP 3112他们所指的(考虑到字符串文字现在是 Unicode,它大部分时间都在讨论如何编写 Python 2 风格的 bytes
对象)。但这就是它的作用。
您可以在交互式解释器中对此进行测试:
>>> 'abc'
'abc'
>>> from __future__ import unicode_literals
>>> 'abc'
u'abc'
因此,在版本 2 中,您将两个 str
对象添加在一起,这很容易。但在版本 1 中,您添加了 unicode
和 str
。这是通过使用默认编码(即 ASCII)自动将 str
转换为 unicode
来实现的,但这是行不通的。
解决此问题的最简单方法是使 project
本身成为 unicode
:
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))
(当然,请确保与源文件的编码声明匹配。)
<小时/>在评论中,您询问:
when using the
__future__
import statement do I still have to define the coding at the beginning of the .py file? # -- coding: 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 中,添加总是安全,而且它也让许多程序员的文本编辑器感到高兴,所以这可能是一个值得保留的习惯,直到我们到达足够远的 future ,没有人记得拉丁语-1 和 Shift-JIS 和 cp1250 等。)
关于python - Django unicode 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17052089/