Python和Unicode:一切都应该是Unicode

时间:2010-12-27 18:15:29

标签: python unicode bytestring

请原谅这个问题:

我用Python编程大约六个月。自学,从Python教程开始,然后是SO,然后只使用谷歌。

这是可悲的部分:没有人告诉我所有字符串都应该是Unicode。不,我不是在撒谎或说谎,但教程在哪里提到它?大多数示例我也看到只使用byte strings而不是Unicode strings.我只是浏览并在SO上遇到了这个问题,其中说明Python中的每个字符串应该是一个Unicode串。这几乎让我哭了!

我读到Python 3.0中的每个字符串都是Unicode,所以我的问题是2.x:

  1. 我应该这样做:

    print u'Some text'或仅print 'Text'

  2. 一切都应该是Unicode,这是否意味着,就像说我有一个tuple

    t = ('First', 'Second'), it should be t = (u'First', u'Second')?

    我读到我可以做一个from __future__ import unicode_literals然后每个字符串都是一个Unicode字符串,但是我也应该在容器内执行此操作吗?

  3. 在读取/写入文件时,我应该使用codecs模块。对?或者我应该只使用标准方式或阅读/写作,并在必要时使用encodedecode

  4. 如果我从说raw_input()获取字符串,我是否应该将其转换为Unicode?

  5. 在2.x中处理所有上述问题的常用方法是什么? from __future__ import unicode_literals声明?

    不好意思成为一个这样的菜鸟,但这改变了我长期以来一直在做的事情,很明显我很困惑。

6 个答案:

答案 0 :(得分:14)

“始终使用Unicode”建议主要是为了更轻松地过渡到Python 3。如果你的代码中有很多非Unicode字符串访问,那么移植它需要做更多的工作。

此外,您不必根据具体情况决定字符串是否应存储为Unicode。您不必更改字符串的类型及其语法,只是因为您更改了其内容。

使用错误的字符串类型也很容易,导致主要工作的代码,或者在Linux中但不在Windows中工作的代码,或者在一个区域设置中但不在另一个区域中的代码。例如,UTF-8语言环境中的for c in "漢字"将遍历每个UTF-8字节(所有六个字节),而不是遍历每个字符;是否打破了事情取决于你对他们做了什么。

原则上,如果你使用Unicode字符串,什么都不应该破坏,但如果你不使用常规字符串,事情可能会中断。

然而,在实践中,在Python 2中使用Unicode字符串是一件痛苦的事。codecs.open没有自动选择正确的语言环境;这失败了:

codecs.open("blar.txt", "w").write(u"漢字")

真正的答案是:

import locale, codecs
lang, encoding = locale.getdefaultlocale()
codecs.open("blar.txt", "w", encoding).write(u"漢字")

...这很麻烦,迫使人们只是打开文件来制作辅助功能。 codecs.open 应该在未指定时自动使用locale中的编码; Python无法使这么简单的操作变得方便,这是人们通常在任何地方使用Unicode的原因之一。

最后请注意,在某些情况下,Unicode字符串在Windows中更为重要。例如,如果您使用的是西部语言环境,并且您有一个名为“汉字”的文件,则必须使用Unicode字符串来访问它,例如。 os.stat(u"漢字")。使用非Unicode字符串访问它是不可能的;它只是看不到文件。

所以,原则上我会说Unicode字符串推荐是合理的,但有一点需要注意,我自己一般都不遵循它。

答案 1 :(得分:11)

不,不是每个字符串“都应该是Unicode”。在你的Python代码中,你知道字符串文字是否需要是Unicode,所以将每个字符串文字都变成Unicode文字没有任何意义。

但是有些情况下你应该使用Unicode。例如,如果您有任意文本输入,请使用Unicode。你迟早会找到一个使用它的非美国人,而且他想在这里找到一个非常好的人。除非您的输入和输出碰巧使用相同的编码,否则您将遇到问题,这是您无法确定的。

所以简而言之,不,字符串不应该是Unicode。 文字应该是。但是YMMV。

具体做法是:

  1. 此处无需使用Unicode。您知道该字符串是否为ASCII。

  2. 取决于您是否需要将这些字符串与Unicode合并。

  3. 两种方式都有效。但是不要在需要时编码解码。解码ASAP,尽可能晚编码。使用编解码器可以很好地工作(或者从Python 2.7开始)。

  4. 呀。

答案 2 :(得分:6)

恕我直言(我的简单规则):

  
      
  1. 我应该这样做:   print u'Some text' or just print 'Text'

  2.   
  3. 一切都应该是Unicode,这是否意味着,就像说我有一个元组:   t = ('First', 'Second'), it should be t = (u'First', u'Second')

  4.   

好吧,只有当我有一些超过ASCII 128的字符时才使用unicode文字:

   print 'New York', u'São Paulo'
   t = ('New York', u'São Paulo')
  
      
  1. 读取/写入文件时,我应该使用编解码器模块。对?或者我应该在需要时使用标准方式或读/写和编码或解码?
  2.   

如果您希望使用unicode文本,请使用编解码器。

  
      
  1. 如果我从raw_input()获取字符串,我是否应该将其转换为Unicode?   

仅当您期望可能转换到具有不同默认编码的另一个系统(包括数据库)的unicode文本时。

EDITED(关于混合unicode和字节串):

>>> print 'New York', 'to', u'São Paulo'
New York to São Paulo
>>> print 'New York' + ' to ' + u'São Paulo'
New York to São Paulo
>>> print "Côte d'Azur" + ' to ' + u'São Paulo'
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: 
     ordinal not in range(128)
>>> print "Côte d'Azur".decode('utf-8') + ' to ' + u'São Paulo'
Côte d'Azur to São Paulo

因此,如果将包含utf-8(或其他非ascii char)的字节字符串与unicode文本混合而不进行显式转换,则会遇到问题,因为默认情况下为ascii。另一种方式似乎是安全的。如果遵循将包含非ascii的每个字符串写为unicode文字的规则,那么你应该没问题。

免责声明:我住在巴西,人们会说葡萄牙语,这是一种含有大量非ascii字符的语言。我的默认编码始终设置为'utf-8'。您的里程可能因英语/ ascii系统而异。

答案 3 :(得分:3)

我只是在这里添加我的个人意见。在其他答案中没有那么长并且详细说明,但也许它也可以提供帮助。

  

print u'Some text'或仅print 'Text'

我确实更喜欢第一个。如果您知道只有Unicode字符串,则会有一个不变量。各种其他语言(C,C ++,Perl,PHP,Ruby,Lua,...)有时会遇到痛苦的问题,因为它们在代码单元序列和整数序列之间缺乏分离。我发现在.NET,Java,Python等中存在严格区分的方法相当简洁。

  

一切都应该是Unicode,这是否意味着,比如说我有一个元组:

     

t = ('First', 'Second'),应为t = (u'First', u'Second')?

  

我读到我可以做一个from __future__ import unicode_literals,然后每个字符串都是一个Unicode字符串,但是我也应该在容器内执行此操作吗?

是。将来的语句仅适用于使用它们的文件,因此您可以在不干扰其他模块的情况下使用它们。我通常会导入Python 2.x模块中的所有期货,以便更容易过渡到3.x.

  

在读取/写入文件时,我应该使用codecs模块。对?或者我应该在需要时使用标准方式或读/写和编码或解码?

您应该使用codecs模块,因为这使得不可能(或至少非常难)意外地将不同编码的表示写入单个文件。当您以文本模式打开文件时,它也是Python 3.x的工作方式。

  

如果我从说raw_input()获取字符串,我是否应该将其转换为Unicode?

我也对此说“是”:在大多数情况下,只处理一种编码更容易,所以我建议尽早转换为Python Unicode字符串。

  

在2.x中处理所有上述问题的常用方法是什么? from __future__ import unicode_literals声明?

我不知道常见的方法是什么,但我一直都在使用这种说法。我在这种方法中遇到的问题很少,而且大多数都与外部库中的错误有关 - 即,NumPy有时需要字节字符串而不记录它。

答案 4 :(得分:2)

在遇到有关Unicode的任何内容之前,您在编写Python代码6个月这一事实意味着字符串的Python 2.x ASCII默认值不会导致任何问题。当然,初学者试图掌握Unicode /代码点/编码本身的想法是一个难以解决的问题;因此,大多数教程自然会绕过它,直到你在基础知识中获得更多的基础。这就是为什么在像Dive Into Python这样的书中,只提到了in later chapters

如果您需要在应用程序中支持Unicode,我建议您查看Kumar McMillan's PyCon 2008 talk on Unicode以获取最佳做法列表。它应该回答你剩下的问题。

答案 5 :(得分:-2)

1/2)就我个人而言,我从未听说过“总是使用unicode”。这对我来说似乎很愚蠢。我想我明白你是否打算支持其他需要unicode支持的语言。但除此之外我不会这样做,看起来更像是一种痛苦而不是它的价值。

3)我只需读取/写入标准方式并在必要时进行编码。