"# -*- coding: utf-8 -*-"、"from __future__ import unicode_literals"和"sys.setdefaultencoding("utf8")"有什么不同?

3

我知道的是:

  1. # -*- coding: utf-8 -*-
    它用于声明Python源代码文件的编码格式。一旦设置了编码名称,Python解析器将使用给定的编码来解释该文件。我称之为"文件编码"。

  2. from __future__ import unicode_literals 我正在使用Python2.7完成我的任务,并使用from __future__ import unicode_literals 来更改字符串的默认类型从"str"变为"unicode"。我称之为"字符串编码"。

  3. sys.setdefaultencoding('utf8') 但有时在Django中会出现错误,例如在管理页面中存储中文,然后访问相关页面:

    UnicodeEncodeError at /admin/blog/vulpaper/29/change/
    'ascii' codec can't encode characters in position 6-13: ordinal not in range(128)
    ....更多的错误信息
    The string that could not be encoded/decoded was: emcms外贸网站管理系统

    针对这个问题,我会在Django设置文件中编写sys.setdefaultencoding('utf8')来解决它。

但实际上,我不了解其中的技术细节。

让我感到困惑的是:
1. 既然我设置了Python源代码文件的编码格式,为什么还要设置字符串编码以确保我的字符串的编码是我喜爱的编码?"文件编码"和"字符串编码"有什么不同?
2. 既然我设置了"文件编码"和"字符串编码",为什么还会出现UnicodeEncodeError错误?


因为Python源代码文件的编码和Python自己编码字符串的方式是两回事。您可以使用UTF-8构建Python文件,但编写ASCII字符串。 - Willem Van Onsem
2
设置 sys.setdefaultencoding 不太可能是任何问题的正确答案。如果您遇到该错误,则可能在您的 __unicode__ 方法中存在错误。 - Daniel Roseman
@DanielRoseman 谢谢,你提到了我,我搜索了相关问题并发现几乎没有人建议新手在项目中使用 sys.setdefaultencoding,所以我从我的设置文件中删除了它。首先我检查了我要存储的中文字符串数据类型,它是unicode,然后我检查了模型,当我将实例方法从 __str__ 更改为 __unicode__ 时,它起作用了!我避免了UnicodeEncodeError。 - Alvin
1个回答

2
通常你需要同时使用文件编码和字面字符串编码,但它们实际上控制的是非常不同的东西,了解这种差异很有帮助。

文件编码

如果你想在源代码中的任何位置(如注释或字面字符串)写入Unicode字符,你必须更改编码以使Python解析器正常工作。设置错误的编码将导致SyntaxError异常。PEP 263详细解释了这个问题以及如何控制解析器的编码。

在Python 2.1中,只能使用基于Latin-1的编码“unicode-escape”编写Unicode字面值。这使得生活和工作在许多亚洲国家等非Latin-1区域的Python用户感到相当不友好。

...

如果没有提供其他编码提示,Python将默认使用ASCII作为标准编码。

Unicode字面字符串

Python 2 使用两种不同的字符串类型,即 unicodestr。当您定义一个字面字符串时,解释器实际上会创建一个新的 str 类型对象来保存这个字面值。
s = "A literal string"
print type(s)

<type 'str'>

TL;DR:如果你想改变这种行为,而是在定义未加前缀的字符串字面量时每次创建一个unicode对象,你可以使用“from __future__ import unicode_literals”。如果你需要理解这个有用的原因,请继续阅读。你可以使用“u”前缀明确地将字面字符串定义为unicode。解释器将会为该字面量创建一个unicode对象。
s = u"A literal string"
print type(s)

<type 'unicode'>

对于ASCII文本,使用str类型就足够了。但是如果你打算操作非ASCII文本,使用unicode类型进行字符级操作才能正确地工作,这一点很重要。下面的例子展示了使用strunicode对完全相同的字面值进行字符级解释的差异。
# -*- coding: utf-8 -*-

def print_characters(s):
    print "String of type {}".format(type(s))
    print "  Length: {} ".format(len(s))
    print "  Characters: " ,
    for c in s:
        print c,
    print
    print


u_lit = u"Γειά σου κόσμε"
s_lit = "Γειά σου κόσμε"

print_characters(u_lit)
print_characters(s_lit)

输出:

String of type <type 'unicode'>
  Length: 14 
  Characters:  Γ ε ι ά   σ ο υ   κ ό σ μ ε

String of type <type 'str'>
  Length: 26 
  Characters:  � � � � � � � �   � � � � � �   � � � � � � � � � �

使用`str`时,它错误地报告长度为`26`个字符,并且迭代字符返回垃圾。另一方面,`unicode`按预期工作。
设置`sys.setdefaultencoding('utf8')`
在stackoverflow上有一个很好的答案解释为什么我们不应该使用它 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接