Почему Python's Hashlib не является строго типизированным? - PullRequest
4 голосов
/ 01 августа 2011

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)

Конечно, это не сбой из-за TypeError, но из-за UnicodeEncodeError.UnicodeEncodeError должен быть вызван, когда вы пытаетесь закодировать юникод в строку.

Я думаю, что я не слишком далек от истины, когда думаю, что Хашлиб молча попытался преобразовать юникод в строку.

Сейчас.Я согласен, hashlib указал, что аргумент hashlib.md5() должен быть строкой или буфером только для чтения, которым является строка Unicode.Но на самом деле это говорит о том, что на самом деле это не так: hashlib.md5() будет правильно работать со строками, и это все.

Конечно, главная проблема, которую это вызывает, состоит в том, что вы получите исключение с некоторыми строками Unicodeи не с некоторыми другими.

Что приводит меня к моим вопросам.Во-первых, у вас есть объяснение, почему hashlib реализует это поведение?Во-вторых, это считается проблемой?В-третьих, есть ли способ исправить это, не меняя сам модуль?

Hashlib - это, в основном, пример, есть несколько других модулей, которые ведут себя одинаково, когда предоставляются строки в кодировке Unicode - что приводит вас к неудобной ситуации, когда ваша программа будет работать с вводом ASCII, но полностью не с акцентами.

Ответы [ 2 ]

12 голосов
/ 01 августа 2011

Это не просто hashlib - Python 2 обрабатывает Unicode во многих местах, пытаясь закодировать его как ascii.Это было одно из самых больших изменений, внесенных в Python 3.

В Python 3 строки имеют кодировку Unicode и ведут себя так, как вы ожидаете: автоматического преобразования в байты нет, и вы должны кодировать их, если хотитеиспользовать байты (например, для хеширования MD5).Я полагаю, что есть хаки, использующие sys.setdefaultencoding, которые включают это поведение в Python 2, но я бы посоветовал не использовать их в рабочей среде, поскольку они влияют на любой код, выполняющийся в этом экземпляре Python.

2 голосов
/ 22 января 2012

Это результат того, что Python 2.x C API делает удобным передавать объекты Unicode в API C, ожидающие строку.

См. Вызов PyArg_ParseTuple * в _hashopenssl.c .

Он попытается закодировать объект Unicode в байтовую строку при синтаксическом анализе его для аргумента 's *'.Если это не может быть закодировано, ошибка будет повышена.Правильнее всего сделать так: всегда вызывать .encode ('utf-8') или любой другой кодек, который требуется вашему приложению, прежде чем пытаться использовать что-либо Unicode в контексте, где имеет смысл только необработанный поток байтов.3.x исправляет это.Вместо этого вы всегда получите дружественное:

TypeError: Unicode-объекты должны быть закодированы перед хэшированием

Вместо любого автоматического кодирования.

...