为啥在python中通过字符串声明unicode?

Posted

技术标签:

【中文标题】为啥在python中通过字符串声明unicode?【英文标题】:Why declare unicode by string in python?为什么在python中通过字符串声明unicode? 【发布时间】:2011-03-11 08:34:44 【问题描述】:

我还在学习python,有一个疑问:

在 python 2.6.x 中,我通常像这样在文件头中声明编码(如PEP 0263)

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

之后,我的字符串就照常写了:

a = "A normal string without declared Unicode"

但是每次我看到一个 python 项目代码时,编码都没有在标题中声明。相反,它在每个字符串中声明如下:

a = u"A string with declared Unicode"

有什么区别?这样做的目的是什么?我知道 Python 2.6.x 默认设置 ASCII 编码,但是它可以被头部声明覆盖,那么每个字符串声明的意义何在?

附录: 好像我把文件编码和字符串编码混在一起了。谢谢你的解释:)

【问题讨论】:

# coding: utf8 已经足够好了,不需要-*- @jellyfish 我猜你的意思是输入# coding: utf-8 应该是#coding=utf-8。 python.org/dev/peps/pep-0263 【参考方案1】:

这并没有设置字符串的格式;它设置文件的格式。即使使用该标头,"hello" 也是一个字节字符串,而不是 Unicode 字符串。要使其成为 Unicode,您将不得不在任何地方使用 u"hello"。标题只是提示读取.py 文件时使用什么格式。

【讨论】:

我当时弄错了,我以为它们是一样的。那么unicode字符串的用途是i18n? @Oscar:大部分情况下是的。如果您正在使用 Django 或其他东西制作网站,并且必须处理使用非 ASCII 字符的人,那么这是另一种可能的用途。【参考方案2】:

标头定义是定义代码本身的编码,而不是运行时生成的字符串。

在没有 utf-8 标头定义的 python 脚本中放入像 2 这样的非 ascii 字符将引发警告

【讨论】:

【参考方案3】:

正如其他人所提到的,这是两件不同的事情。

当您指定 # -*- coding: utf-8 -*- 时,您是在告诉 Python 您保存的源文件是 utf-8。 Python 2 的默认值是 ASCII(对于 Python 3,它是 utf-8)。这只会影响解释器如何读取文件中的字符。

一般来说,无论编码是什么,将高 unicode 字符嵌入到文件中可能不是最好的主意;您可以使用字符串 unicode 转义,它适用于任何一种编码。


当您声明一个前面带有u 的字符串时,例如u'This is a string',它告诉Python 编译器该字符串是Unicode,而不是字节。这主要由解释器透明地处理;最明显的区别是您现在可以在字符串中嵌入 unicode 字符(也就是说,u'\u2665' 现在是合法的)。您可以使用from __future__ import unicode_literals 将其设为默认值。

这仅适用于 Python 2;在 Python 3 中默认是 Unicode,你需要在前面指定一个b(比如b'These are bytes',声明一个字节序列)。

【讨论】:

感谢您的解释!我会将其设置为已接受,因为它是最完整的:) Python 2 的默认源编码是 ascii 在文件中嵌入高 unicode 字符实际上是个好主意。我怀疑非英语使用者想在他们的字符串中阅读 unicode 转义符。 @Mark:感谢 ASCII 更正;我快速浏览了 PEP (python.org/dev/peps/pep-0263),它在序言中谈到了 Latin-1。在大多数情况下,我认为在文件中嵌入高 unicode 字符并不是一个好主意。当然,如果您在源文件中编写大量非英语字符串,它会变得更容易,但您通常这样做是为了向用户显示,并且您可能应该在单独的地方定义它们。一个配置错误的文本编辑器可能会损坏所有这些字符。 同意如果您正在编写 i18nalized 应用程序,但请考虑您是中国还是法国程序员。不仅是琴弦,还有 cmets。 Python 在源编码方面非常灵活,这很棒。 Python 3 甚至可以在变量名中包含非 ASCII 字符。【参考方案4】:

正如其他人所说,# coding: 指定了保存源文件的编码。这里有一些例子来说明这一点:

保存在磁盘上的文件为 cp437(我的控制台编码),但未声明编码

b = 'über'
u = u'über'
print b,repr(b)
print u,repr(u)

输出:

  File "C:\ex.py", line 1
SyntaxError: Non-ASCII character '\x81' in file C:\ex.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

添加了# coding: cp437 的文件输出:

über '\x81ber'
über u'\xfcber'

起初,Python 不知道编码并抱怨非 ASCII 字符。一旦它知道编码,字节字符串就会得到实际在磁盘上的字节。对于 Unicode 字符串,Python 读取 \x81,知道在 cp437 中是 ü,并将其解码为 ü 的 Unicode 代码点,即 U+00FC。打印字节字符串时,Python 直接将十六进制值81 发送到控制台。打印 Unicode 字符串时,Python 正确检测到我的控制台编码为 cp437,并将 Unicode ü 转换为 ü 的 cp437 值。

以 UTF-8 声明和保存的文件如下所示:

├╝ber '\xc3\xbcber'
über u'\xfcber'

在 UTF-8 中,ü 被编码为十六进制字节 C3 BC,因此字节字符串包含这些字节,但 Unicode 字符串与第一个示例相同。 Python 读取这两个字节并正确解码。 Python 错误地打印了字节字符串,因为它将代表 ü 的两个 UTF-8 字节直接发送到我的 cp437 控制台。

这里的文件声明为 cp437,但以 UTF-8 保存:

├╝ber '\xc3\xbcber'
├╝ber u'\u251c\u255dber'

字节字符串仍然获取磁盘上的字节(UTF-8 十六进制字节C3 BC),但将它们解释为两个 cp437 字符而不是单个 UTF-8 编码字符。这两个字符被转换为 Unicode 代码点,并且所有内容都打印不正确。

【讨论】:

【参考方案5】:

我制作了以下名为 unicoder 的模块,以便能够对变量进行转换:

import sys
import os

def ustr(string):

    string = 'u"%s"'%string

    with open('_unicoder.py', 'w') as script:

        script.write('# -*- coding: utf-8 -*-\n')
        script.write('_ustr = %s'%string)

    import _unicoder
    value = _unicoder._ustr

    del _unicoder
    del sys.modules['_unicoder']

    os.system('del _unicoder.py')
    os.system('del _unicoder.pyc')

    return value

然后在您的程序中,您可以执行以下操作:

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

from unicoder import ustr

txt = 'Hello, Unicode World'
txt = ustr(txt)

print type(txt) # <type 'unicode'>

【讨论】:

以上是关于为啥在python中通过字符串声明unicode?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在 Python 中通过 reduce 对列表进行排序的代码会引发错误?

当默认编码为 ASCII 时,为啥 Python 会打印 unicode 字符?

在python中通过分隔符拆分字符串

为啥在 PHP 中通过引用传递?

如何在python中通过多种格式格式化日期字符串

mysql中通过my.cnf设置默认字符集utf-8