如何在Python doctests中包含unicode字符串?

21 投票
5 回答
4700 浏览
提问于 2025-04-15 16:00

我正在处理一些需要操作unicode字符串的代码。我想为它写一些测试,但遇到了一些麻烦。下面是一个简单的例子,说明了这个问题:

# -*- coding: utf-8 -*-
def mylen(word):
  """
  >>> mylen(u"áéíóú")
  5
  """
  return len(word)

print mylen(u"áéíóú")

首先,我们运行代码,看看print mylen(u"áéíóú")的预期输出是什么。

$ python mylen.py
5

接下来,我们对它运行测试,看看问题出在哪里。

$ python -m
5
**********************************************************************
File "mylen.py", line 4, in mylen.mylen
Failed example:
    mylen(u"áéíóú")
Expected:
    5
Got:
    10
**********************************************************************
1 items had failures:
   1 of   1 in mylen.mylen
***Test Failed*** 1 failures.

那么,我该如何测试mylen(u"áéíóú")的结果是否等于5呢?

5 个回答

2

这似乎是Python中一个已知但尚未解决的问题。你可以在这里查看相关的未解决问题 这里这里

这也不奇怪,因为在Python 3中,所有字符串都是Unicode格式,所以可以对其进行修改,使其正常工作:

def mylen(word):
  """
  >>> mylen("áéíóú")
  5
  """
  return len(word)

print(mylen("áéíóú"))
6

Python 2.6.6 对于处理 Unicode 输出不是很友好,但我们可以通过以下方法来解决这个问题:

  • 之前提到的一个小技巧,就是使用 sys.setdefaultencoding("UTF-8")
  • 使用 Unicode 文档字符串(上面也提到过,非常感谢)
  • 还有 print 语句。

在我的例子中,这个文档字符串告诉我们测试失败了:

def beatiful_units(*units):
    u'''Returns nice string like 'erg/(cm² sec)'.

    >>> beatiful_units(('erg', 1), ('cm', -2), ('sec', -1))
    u'erg/(cm² sec)'
    '''

并且有一个“错误”信息

Failed example:
    beatiful_units(('erg', 1), ('cm', -2), ('sec', -1))
Expected:
    u'erg/(cm² sec)'
Got:
    u'erg/(cm\xb2 sec)'

通过使用 print,我们可以解决这个问题:

def beatiful_units(*units):
    u'''Returns nice string like 'erg/(cm² sec)'.

    >>> print beatiful_units(('erg', 1), ('cm', -2), ('sec', -1))
    erg/(cm² sec)
    '''
21

如果你想要使用unicode字符串,就得用unicode文档字符串!记得加上u哦!

# -*- coding: utf-8 -*-
def mylen(word):
  u"""        <----- SEE 'u' HERE
  >>> mylen(u"áéíóú")
  5
  """
  return len(word)

print mylen(u"áéíóú")

这样做是可以的——只要测试通过就行。对于Python 2.x,你还需要另一个小技巧,才能让详细的文档测试模式正常工作,或者在测试失败时得到正确的错误追踪信息:

if __name__ == "__main__":
    import sys
    reload(sys)
    sys.setdefaultencoding("UTF-8")
    import doctest
    doctest.testmod()

注意!只在调试的时候使用setdefaultencoding。对于文档测试可以接受,但绝对不要在你的正式代码中使用。

撰写回答