为啥在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 对列表进行排序的代码会引发错误?