Подтвердить что ты не робот

Python: конвертировать сложный словарь строк из Unicode в ASCII

Возможный дубликат:
Как получить строку Объекты вместо Unicode из JSON в Python?

У меня много входных данных, поскольку многоуровневые словари анализируются из вызовов API JSON. Строки все в юникоде, что означает, что существует много u'stuff like this'. Я использую jq, чтобы поиграть с результатами и вам нужно преобразовать эти результаты в ASCII.

Я знаю, что могу написать функцию, чтобы просто преобразовать ее так:

def convert(input):
    if isinstance(input, dict):
        ret = {}
        for stuff in input:
            ret = convert(stuff)
    elif isinstance(input, list):
        ret = []
        for i in range(len(input))
            ret = convert(input[i])
    elif isinstance(input, str):
        ret = input.encode('ascii')
    elif :
        ret = input
    return ret

Это даже правильно? Не уверен. Это не то, что я хочу спросить вас, хотя.

То, о чем я прошу, это типичное решение проблемы с грубой силой. Должен быть лучший способ. Более пифонический путь. Я не эксперт по алгоритмам, но этот тоже не выглядит особенно быстрым.

Так есть лучший способ? Или, если нет, можно ли улучшить эту функцию...?


Редактирование после ответа

Ответ от Марка Эмери является правильным, но я хотел бы опубликовать его модифицированную версию. Его функция работает на Python 2.7+, и я на 2.6, поэтому мне пришлось ее преобразовать:

def convert(input):
    if isinstance(input, dict):
        return dict((convert(key), convert(value)) for key, value in input.iteritems())
    elif isinstance(input, list):
        return [convert(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input
4b9b3361

Ответ 1

Рекурсия выглядит как способ пойти сюда, но если вы на python 2.xx, вы хотите проверить unicode, а не str (тип str представляет собой строку байтов, а unicode введите строку символов Юникода, а не наследуется от другой, и это строки типа Unicode, которые отображаются в интерпретаторе с au перед ними). ​​

Там также немного синтаксическая ошибка в вашем опубликованном коде (конечный elif: должен быть else), и вы не возвращаете ту же структуру в том случае, когда ввод является либо словарем, либо списком. (В случае словаря вы возвращаете преобразованную версию финального ключа, а в случае списка вы возвращаете преобразованную версию конечного элемента. Правильно!)

Вы также можете сделать свой код симпатичным и Pythonic с помощью понятий.

Вот, вот что я бы рекомендовал:

def convert(input):
    if isinstance(input, dict):
        return {convert(key): convert(value) for key, value in input.iteritems()}
    elif isinstance(input, list):
        return [convert(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

Одна последняя вещь. Я изменил encode('ascii') на encode('utf-8'). Мое рассуждение таково: любая строка юникода, содержащая только символы в наборе символов ASCII, будет представлена ​​одной и той же строкой байта при кодировании в ASCII, как при кодировании в utf-8, поэтому использование utf-8 вместо ASCII не может сломать что-либо и изменение будет невидимым до тех пор, пока строки unicode, с которыми вы имеете дело, используют только символы ASCII. Однако это изменение расширяет область действия функции, чтобы иметь возможность обрабатывать строки символов из всего набора символов Юникода, а не только ASCII, если такая необходимость когда-либо понадобится.