如何使Python 2.x在将字符串强制转换为Unicode时发出警告?

4

编码错误的一个常见来源是,当你将字符串和unicode字符串一起使用加号进行拼接时,Python 2会默默地将字符串强制转换为unicode类型。这可能会导致混合编码问题,并且很难调试。

例如:

import urllib
import webbrowser
name = raw_input("What's your name?\nName: ")
greeting = "Hello, %s" % name
if name == "John":
    greeting += u' (Feliz cumplea\xf1os!)'
webbrowser.open('http://lmgtf\x79.com?q=' + urllib.quote_plus(greeting))

如果输入“John”,它会因为一个神秘的错误而失败:

/usr/lib/python2.7/urllib.py:1268: UnicodeWarning: Unicode equal comparison faile
d to convert both arguments to Unicode - interpreting them as being unequal
  return ''.join(map(quoter, s))
Traceback (most recent call last):
  File "feliz.py", line 7, in <module>
    webbrowser.open('http://lmgtf\x79.com?q=' + urllib.quote_plus(greeting))
  File "/usr/lib/python2.7/urllib.py", line 1273, in quote_plus
    s = quote(s, safe + ' ')
  File "/usr/lib/python2.7/urllib.py", line 1268, in quote
    return ''.join(map(quoter, s))
KeyError: u'\xf1'

当实际强制转换发生在很远的地方时,跟踪实际错误特别困难。

如何配置Python,在字符串被强制转换为Unicode时立即给出警告或异常?


嗯...我不得不篡改“lmgtf y.com”的URL,因为否则SO不允许我发布它... - Mu Mind
1
据我所知,这是不可配置的,不幸的是。[我认为那个特定的网站被封锁是因为它只是用作一个讽刺性的rickroll。在meta上有一些讨论。] - DSM
你为什么不一开始就使用unicode字面量,需要时再进行编码呢? - Ignacio Vazquez-Abrams
2
我认为这里有些混淆。从最近的一个回答中,我认为@MuMind知道unicode是如何工作的,并且正在询问是否有一种方法在Python 2中获得类似Python 3的自动强制拒绝。我怀疑这是由于一个最近的问题所激发的,其中提问者似乎已经陷入了比在3中更难解决的麻烦中。 - DSM
2
不错的问题。我认为这应该是Python 2.x功能的价值所在,是否仍会添加到该分支中——一个命令行开关,用于在混合两种类型时引发错误。 - jsbueno
1
特别是因为它对于转换到Python 3非常重要,这也是Python 2.7分支的重点所在。至少,Unicode-nazi工具应该得到更多的宣传。 - Mu Mind
2个回答

4

在问了这个问题后,我又做了一些研究,并找到了完美的答案。Armin Ronacher创建了一个名为unicode-nazi的小工具。只需安装它并像这样运行您的程序:

python -Werror -municodenazi myprog.py

当类型转换发生时,您会得到一个回溯(traceback),其中指出了错误的位置:

Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "SITE-PACKAGES/unicodenazi.py", line 128, in <module>
    main()
  File "SITE-PACKAGES/unicodenazi.py", line 119, in main
    execfile(sys.argv[0], main_mod.__dict__)
  File "myprog.py", line 4, in <module>
    print foo()
  File "myprog.py", line 2, in foo
    return 'bar' + u'baz'
  File "SITE-PACKAGES/unicodenazi.py", line 34, in warning_decode
    stacklevel=2)
UnicodeWarning: Implicit conversion of str to unicode

如果你正在处理触发了隐式强制转换的Python库,而且你无法捕获异常或以其他方式解决问题,你可以省略-Werror

python -municodenazi myprog.py

当发生时,至少能在stderr上看到一个警告:

/SITE-PACKAGES/unicodenazi.py:119: UnicodeWarning: Implicit conversion of str to unicode
  execfile(sys.argv[0], main_mod.__dict__)
barbaz

0

这个错误一点也不神秘。从中我可以看出urllib.quote()(由quote_plus()调用)不能很好地处理Unicode。快速搜索一下,我找到了前一个SO问题,询问Unicode安全的替代方案。不幸的是,似乎没有合适的替代方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接