4

Python 应该是强类型的。

例如:'abc'['1']不起作用,因为您应该在那里提供一个整数,而不是一个字符串。将引发错误,您可以继续并更正它。

但 hashlib 并非如此。确实,请尝试以下操作:

import hashlib
hashlib.md5('abc') #Works OK        

hashlib.md5(1) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: md5() argument 1 must be string or read-only buffer, not int

hashlib.md5(u'abc') #Works, but shouldn't : this is unicode, not str.

haslib.md5(u'é')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)

当然,它不是因为 a 而失败TypeError,而是因为UnicodeEncodeError. UnicodeEncodeError当您尝试将 unicode 编码为字符串时应该引发。

当我的猜测是 Hashlib 默默地尝试将 unicode 转换为字符串时,我认为我离事实并不太远。

现在。我同意,hashlib 表明参数hashlib.md5()应该是字符串或只读缓冲区,即 unicode 字符串。但这实际上表明它实际上不是:hashlib.md5()将与字符串一起正常工作,仅此而已。

当然,这导致的主要问题是您会得到一些 unicode 字符串的异常,而不是其他一些字符串。

这引出了我的问题。首先,您对 hashlib 实现这种行为的原因有什么解释吗?第二,它是否被认为是一个问题?第三,有没有办法在不改变模块本身的情况下解决这个问题?

Hashlib 基本上就是一个例子,当提供 unicode 字符串时,还有几个其他模块的行为相同 - 这会导致您的程序将使用 ASCII 输入但完全因重音而失败的情况令人不舒服。

4

2 回答 2

12

它不仅仅是 hashlib - Python 2 通过尝试将其编码为 ascii 在许多地方处理 Unicode。这是 Python 3 的重大变化之一。

在 Python 3 中,字符串是 unicode,它们的行为与您期望的一样:没有自动转换为字节,如果您想使用字节,则必须对它们进行编码(例如,用于 MD5 散列)。我相信在 Python 2 中有一些黑客sys.setdefaultencoding可以启用这种行为,但我建议不要在生产中使用它们,因为它们会影响在该 Python 实例中运行的任何代码。

于 2011-08-01T16:50:21.517 回答
2

这是 Python 2.x C API 的结果,它可以方便地将 Unicode 对象传递给需要字符串的 C API。

请参阅 _hashopenssl.c 中的PyArg_ParseTuple * 调用。

在解析 's*' 参数时,它将尝试将 Unicode 对象编码为字节字符串。如果无法对其进行编码,则会引发错误。正确的做法是在尝试在只有原始字节流有意义的上下文中使用任何 Unicode 之前,始终调用 .encode('utf-8') 或您的应用程序需要的任何其他编解码器。

Python 3.x 修复了这个问题。相反,你总是会得到一个友好的:

TypeError:Unicode 对象必须在散列之前进行编码

而不是任何自动编码。

于 2012-01-22T06:46:48.277 回答