(unicode错误)'unicodeescape'编解码器无法解码字节 - 含有'\u'的字符串

26 投票
4 回答
35844 浏览
提问于 2025-04-17 03:22

我在写Python 2.6的代码,但考虑到将来可能会用到Python 3,所以我觉得在一些模块的顶部加上

from __future__ import unicode_literals

是个好主意。换句话说,我是在主动制造一些麻烦(为了将来避免这些麻烦),但我可能缺少一些重要的知识。我希望能够传递一个表示文件路径的字符串,并像这样简单地创建一个对象:

MyObject('H:\unittests')

Python 2.6中,这样做没问题,不需要使用双反斜杠或者原始字符串,即使是以'\u..'开头的目录,这正是我想要的。在__init__方法中,我确保所有单个的\都被解释为'\\',包括那些在特殊字符前面的,比如\a\b\f\n\r\t\v(只有\x仍然是个问题)。此外,使用(本地)编码将给定字符串解码为unicode也能按预期工作。

为了准备Python 3.x,我在编辑器中模拟我的实际问题(从一个干净的Python 2.6控制台开始),发生了以下情况:

>>> '\u'
'\\u'
>>> r'\u'
'\\u'

(到这里都正常:'\u'被控制台用本地编码编码)

>>> from __future__ import unicode_literals
>>> '\u'
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: end of string in escape sequence

换句话说,这个(unicode)字符串根本没有被解释为unicode,也没有自动用本地编码解码。即使是原始字符串也是如此:

>>> r'\u'
SyntaxError: (unicode error) 'rawunicodeescape' codec can't decode bytes in position 0-1: truncated \uXXXX

对于u'\u'也是一样:

>>> u'\u'
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: end of string in escape sequence

此外,我本来期待isinstance(str(''), unicode)返回True(但实际上并没有),因为导入unicode_literals应该让所有字符串类型都变成unicode。(编辑:)因为在Python 3中,所有字符串都是Unicode字符的序列,我本来期待str('')返回这样的unicode字符串,type(str(''))应该同时是<type 'unicode'><type 'str'>(因为所有字符串都是unicode),但我也意识到<type 'unicode'>并不是<type 'str'>。真是让人困惑……

问题

  • 我该如何最好地传递包含'\u'的字符串?(不想写'\\u')
  • from __future__ import unicode_literals真的实现了所有与Python 3相关的unicode变化吗,这样我就能得到一个完整的Python 3字符串环境?

编辑:

在Python 3中,<type 'str'>是一个Unicode对象,而<type 'unicode'>根本不存在。在我的情况下,我想为Python 2(.6)写代码,使其在Python 3中也能工作。但是当我import unicode_literals时,我无法检查一个字符串是否是<type 'unicode'>,因为:

  • 我认为unicode不在命名空间中
  • 如果unicode在命名空间中,<type 'str'>的字面量在同一个模块中创建时仍然是unicode
  • type(mystring)在Python 3中对于unicode字面量总是返回<type 'str'>

我的模块通常通过在顶部加上# coding: UTF-8注释来编码为'utf-8',而我的locale.getdefaultlocale()[1]返回'cp1252'。所以如果我从控制台调用MyObject('çça'),在Python 2中它会被编码为'cp1252',而从模块调用MyObject('çça')时则是'utf-8'。在Python 3中,它不会被编码,而是一个unicode字面量。

编辑:

我已经放弃了希望,认为可以避免在u(或者x)前面使用'\'。我也理解导入unicode_literals的限制。然而,从模块到控制台以及反向传递字符串的许多可能组合,以及每种不同编码的情况,再加上导入unicode_literals与否和Python 2与Python 3之间的差异,让我想通过实际测试来创建一个概述。因此下面有一个表格。enter image description here

换句话说,type(str(''))在Python 3中不会返回<type 'str'>,而是<class 'str'>,所有Python 2的问题似乎都被避免了。

4 个回答

-1

我在Python 3上试了这个:

import os

os.path.abspath("yourPath")

结果成功了!

0

对我来说,这个问题跟版本不更新有关,这里指的是 numpy 这个库。

要解决这个问题:

conda install -f numpy
20

据我所知,from __future__ import unicode_literals 这个语句的作用就是让所有的字符串字面量都变成unicode类型,而不是普通字符串类型。也就是说:

>>> type('')
<type 'str'>
>>> from __future__ import unicode_literals
>>> type('')
<type 'unicode'>

不过,strunicode仍然是不同的类型,它们的表现和以前一样。

>>> type(str(''))
<type 'str'>

总是属于str类型。

关于你提到的r'\u'问题,这是设计使然,因为在没有unicode_literals的情况下,它等同于ru'\u'。根据文档:

当'r'或'R'前缀与'u'或'U'前缀一起使用时,\uXXXX和\UXXXXXXXX转义序列会被处理,而所有其他的反斜杠则会保留在字符串中。

这可能是因为python2系列的词法分析器的工作方式。在python3中,它的表现会像你(和我)预期的那样。

你可以输入两个反斜杠,这样\u就不会被解释,但你会得到两个反斜杠!

反斜杠可以用前面的反斜杠进行转义;不过,这两个反斜杠都会保留在字符串中。

>>> ur'\\u'
u'\\\\u'

所以在我看来,你有两个简单的选择:

  • 不使用原始字符串,并转义你的反斜杠(与python3兼容):

    'H:\\unittests'

  • 聪明一点,利用unicode代码点(与python3兼容):

    r'H:\u005cunittests'

撰写回答