Вы действительно должны нервничать.Сама идея, что в какой-то структуре данных может быть смесь байтов и текста, просто ужасна.Это нарушает основной принцип работы со строковыми данными: декодировать во время ввода, работать исключительно в Unicode, кодировать во время вывода.
Обновление в ответ на комментарий:
Вы собираетесь вывести некоторыесвоего рода HTTP-запрос.Это должно быть подготовлено как строка байтов.Тот факт, что urllib.urlencode не способен правильно подготовить эту байтовую строку, если в вашем объявлении есть символы Юникода с порядковым номером> = 128, действительно вызывает сожаление.Если у вас есть смесь байтовых строк и юникодных строк, вы должны быть осторожны.Давайте рассмотрим, что делает urlencode ():
>>> import urllib
>>> tests = ['\x80', '\xe2\x82\xac', 1, '1', u'1', u'\x80', u'\u20ac']
>>> for test in tests:
... print repr(test), repr(urllib.urlencode({'a':test}))
...
'\x80' 'a=%80'
'\xe2\x82\xac' 'a=%E2%82%AC'
1 'a=1'
'1' 'a=1'
u'1' 'a=1'
u'\x80'
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "C:\python27\lib\urllib.py", line 1282, in urlencode
v = quote_plus(str(v))
UnicodeEncodeError: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
Последние два теста демонстрируют проблему с urlencode ().Теперь давайте посмотрим на тесты str.
Если вы настаиваете на наличии смеси, то вам следует как минимум убедиться, что объекты str закодированы в UTF-8.
'\ x80'подозрительно - это не результат any_valid_unicode_string.encode (' utf8 ').
' \ xe2 \ x82 \ xac 'в порядке;это результат использования u '\ u20ac'.encode (' utf8 ').
' 1 'в порядке - все символы ASCII в порядке на входе в функцию urlencode (), которая будет кодировать в процентах, например,'% ', еслиобязательно.
Вот рекомендуемая функция преобразователя.Он не изменяет входные данные и не возвращает их (как у вас);это возвращает новый диктат.Это вызывает исключение, если значение является объектом str, но не является допустимой строкой UTF-8.Кстати, ваше беспокойство по поводу того, что он не обрабатывает вложенные объекты, немного неверно направлено - ваш код работает только с диктовками, а концепция вложенных диктов на самом деле не работает.
def encoded_dict(in_dict):
out_dict = {}
for k, v in in_dict.iteritems():
if isinstance(v, unicode):
v = v.encode('utf8')
elif isinstance(v, str):
# Must be encoded in UTF-8
v.decode('utf8')
out_dict[k] = v
return out_dict
и вот вывод, используя те же тесты в обратном порядке (потому что на этот раз противный находится впереди):
>>> for test in tests[::-1]:
... print repr(test), repr(urllib.urlencode(encoded_dict({'a':test})))
...
u'\u20ac' 'a=%E2%82%AC'
u'\x80' 'a=%C2%80'
u'1' 'a=1'
'1' 'a=1'
1 'a=1'
'\xe2\x82\xac' 'a=%E2%82%AC'
'\x80'
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 8, in encoded_dict
File "C:\python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
>>>
Помогает ли это?