json.dumps при sort_keys=true не умеет сравнивать числа и строки

Мне нужно сдампить данные в json (ключами могут быть и числа, и строки, может быть вложенные словари/списки). Хочется также поддерживать сортировку ключей.

Проблема в том, что код

import json
print(json.dumps({1: 1, '2': '2'}, sort_keys=True))

падает с ошибкой

TypeError: '<' not supported between instances of 'str' and 'int'

Причины падения очевидны, а вот как правильно и красиво исправить не очень понятно.

Очевидный вариант - рекурсивно пробежаться по словарю и привести все ключи к строкам. Только не хочется городить велосипеды, может кто-нибудь уже решал такую проблему более элегантно?


Ответы (2 шт):

Автор решения: Amgarak

Просто рекурсивно обойти и не мучиться:

import json

def keys_to_string(d):
    if isinstance(d, dict):
        return {str(k): keys_to_string(v) for k, v in d.items()}
    elif isinstance(d, list):
        return [keys_to_string(i) for i in d]
    return d

data = {'2': 1, 1: '2', 6: {'4': 4, 5: 5}, '3': [6, 7, {8: '8'}]}

string_data = keys_to_string(data)

json_string = json.dumps(string_data, sort_keys=True, indent=2)
print(json_string)

Вывод:

{
  "1": "2",
  "2": 1,
  "3": [
    6,
    7,
    {
      "8": "8"
    }
  ],
  "6": {
    "4": 4,
    "5": 5
  }
}

[Program finished]
→ Ссылка
Автор решения: Spatz

Можно прогнать первый этап без сортировки:

normalized = json.loads(json.dumps({1: 1, '2': '2'}))

а затем уже:

json.dumps(normalized, sort_keys=True)
→ Ссылка