Как красиво вывести вложенные словари?
Как я могу красиво отформатировать словарь глубиной около 4 в Python? Я пробовал использовать функцию pprint()
, но она не сработала:
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)
Я хочу, чтобы каждое уровень вложенности имел табуляцию ("\t"
), чтобы получить что-то вроде этого:
key1
value1
value2
key2
value1
value2
и так далее.
Как это сделать?
5 ответ(ов)
Сначала я подумал, что JSON-сериализатор, вероятно, неплохо справляется с вложенными словарями, так что я решил использовать его:
>>> import json
>>> print(json.dumps({'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}},
... sort_keys=True, indent=4))
{
"a": 2,
"b": {
"x": 3,
"y": {
"t1": 4,
"t2": 5
}
}
}
Этот пример показывает, как можно легко сериализовать вложенные словари в формате JSON с помощью модуля json
в Python. Вы можете использовать параметр sort_keys=True
, чтобы отсортировать ключи, и indent=4
, чтобы отформатировать вывод с отступами, что делает его более читаемым.
Не уверен, как именно вы хотите, чтобы выглядел форматирование, но вы можете начать с такой функции:
def pretty(d, indent=0):
for key, value in d.items():
print('\t' * indent + str(key))
if isinstance(value, dict):
pretty(value, indent+1)
else:
print('\t' * (indent+1) + str(value))
Эта функция принимает словарь и рекурсивно обходит его, выводя ключи и значения с соответствующим отступом для вложенных словарей. Вы можете изменить форматирование в зависимости от ваших требований.
Вы можете распечатать ваш словарь в красивом виде следующим образом, если имя вашего словаря — yasin
:
import json
print(json.dumps(yasin, indent=2))
Либо, что безопаснее, можно воспользоваться таким вариантом:
print(json.dumps(yasin, indent=2, default=str))
Первый способ позволяет форматировать вывод с отступами, делая его более читаемым. Второй способ добавляет аргумент default=str
, который позволяет избежать ошибок, если в словаре есть неопознанные типы данных, преобразуя их в строки.
На данный момент, я не столкнулся с ни одним "красивым" принтером, который хотя бы как-то имитировал бы вывод интерпретатора Python с простым форматированием, поэтому вот мой вариант:
class Formatter(object):
def __init__(self):
self.types = {}
self.htchar = '\t'
self.lfchar = '\n'
self.indent = 0
self.set_formater(object, self.__class__.format_object)
self.set_formater(dict, self.__class__.format_dict)
self.set_formater(list, self.__class__.format_list)
self.set_formater(tuple, self.__class__.format_tuple)
def set_formater(self, obj, callback):
self.types[obj] = callback
def __call__(self, value, **args):
for key in args:
setattr(self, key, args[key])
formater = self.types.get(type(value), self.types[object])
return formater(self, value, self.indent)
def format_object(self, value, indent):
return repr(value)
def format_dict(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + repr(key) + ': ' +
(self.types.get(type(value[key]), self.types[object]))(self, value[key], indent + 1)
for key in value
]
return '{%s}' % (','.join(items) + self.lfchar + self.htchar * indent)
def format_list(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + (self.types.get(type(item), self.types[object]))(self, item, indent + 1)
for item in value
]
return '[%s]' % (','.join(items) + self.lfchar + self.htchar * indent)
def format_tuple(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + (self.types.get(type(item), self.types[object]))(self, item, indent + 1)
for item in value
]
return '(%s)' % (','.join(items) + self.lfchar + self.htchar * indent)
Чтобы инициализировать форматтер, используйте:
pretty = Formatter()
Вы можете добавить форматтеры для определенных типов, просто создайте для этого функцию, как показано ниже, и привяжите её к нужному типу с помощью метода set_formater
:
from collections import OrderedDict
def format_ordereddict(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) +
"(" + repr(key) + ', ' + (self.types.get(type(value[key]), self.types[object]))(self, value[key], indent + 1) + ")"
for key in value
]
return 'OrderedDict([%s])' % (','.join(items) +
self.lfchar + self.htchar * indent)
pretty.set_formater(OrderedDict, format_ordereddict)
По историческим причинам, я оставил предыдущий "красивый" принтер, который был функцией вместо класса, но оба варианта можно использовать одинаково, версия с классом просто позволяет делать гораздо больше:
def pretty(value, htchar='\t', lfchar='\n', indent=0):
nlch = lfchar + htchar * (indent + 1)
if isinstance(value, dict):
items = [
nlch + repr(key) + ': ' + pretty(value[key], htchar, lfchar, indent + 1)
for key in value
]
return '{%s}' % (','.join(items) + lfchar + htchar * indent)
elif isinstance(value, list):
items = [
nlch + pretty(item, htchar, lfchar, indent + 1)
for item in value
]
return '[%s]' % (','.join(items) + lfchar + htchar * indent)
elif isinstance(value, tuple):
items = [
nlch + pretty(item, htchar, lfchar, indent + 1)
for item in value
]
return '(%s)' % (','.join(items) + lfchar + htchar * indent)
else:
return repr(value)
Чтобы использовать его:
>>> a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':pretty,'unicode':u'\xa7',("tuple","key"):"valid"}
>>> a
{'function': <function pretty at 0x7fdf555809b0>, 'tuple': ('a', 'b', 1, 2), 'list': ['a', 'b', 1, 2], 'dict': {'a': 1, 2: 'b'}, 'unicode': u'\xa7', ('tuple', 'key'): 'valid'}
>>> print(pretty(a))
{
'function': <function pretty at 0x7fdf555809b0>,
'tuple': (
'a',
'b',
1,
2
),
'list': [
'a',
'b',
1,
2
],
'dict': {
'a': 1,
2: 'b'
},
'unicode': u'\xa7',
('tuple', 'key'): 'valid'
}
По сравнению с другими версиями:
- Это решение напрямую проверяет тип объекта, так что вы можете "красиво" распечатать почти всё, а не только списки или словари.
- Не имеет зависимостей.
- Всё помещается в строку, так что вы можете делать с этим что угодно.
- Как класс, так и функция были протестированы и работают с Python 2.7 и 3.4.
- Вы можете иметь любые типы объектов внутри, выводится их представление, а не содержимое (т.е. строки обрамляются кавычками, юникод-строки полностью представлены и т.д.).
- В версии с классом вы можете добавлять форматирование для любого типа объекта или изменять уже определенные.
- Ключи могут иметь любой допустимый тип.
- Символы отступа и новой строки могут быть изменены на любые желаемые.
- Словари, списки и кортежи выводятся в "красивом" формате.
Чтобы решить вашу проблему с ошибкой типа TypeError: Object of type 'datetime' is not JSON serializable
, вам нужно передать параметр default
, который укажет, как обрабатывать объекты, не поддающиеся сериализации в JSON. Вы можете сделать это, передав default=str
, следующим образом:
print(json.dumps(my_dictionary, indent=4, default=str))
Если вы также хотите отсортировать ключи словаря перед сериализацией, вы можете использовать параметр sort_keys
:
print(json.dumps(my_dictionary, sort_keys=True, indent=4, default=str))
Таким образом, вы сможете успешно справиться с сериализацией словаря, содержащего значения типа datetime
.
Преобразование списка словарей в DataFrame pandas
Почему использовать dict.get(key) вместо dict[key]?
Как преобразовать вложенный словарь Python в объект?
Ошибка: "'dict' объект не имеет метода 'iteritems'"
Есть ли питоний способ объединить два словаря (сложив значения для ключей, которые присутствуют в обоих)?