Как красиво печатать вложенные словари?
Как я могу напечатать словарь с глубиной ~ 4 в Python? Я попробовал довольно печатать с pprint()
, но это не сработало:
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)
Я просто хочу отступы ("\t"
) для каждого вложения, так что я получаю что-то вроде этого:
key1
value1
value2
key2
value1
value2
и т.д..
Как я могу это сделать?
Ответы
Ответ 1
Я не уверен, как именно вы хотите, чтобы форматирование выглядело, но вы могли бы начать с такой функции:
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))
Ответ 2
Моя первая мысль заключалась в том, что сериализатор 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
}
}
}
Ответ 3
Вы можете попробовать YAML через PyYAML. Его выход может быть точно настроен. Я предлагаю начать со следующего:
print yaml.dump(data, allow_unicode=True, default_flow_style=False)
Результат очень читабельен; его можно также проанализировать на Python, если это необходимо.
Edit:
Пример:
>>> import yaml
>>> data = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
>>> print yaml.dump(data, default_flow_style=False)
a: 2
b:
x: 3
y:
t1: 4
t2: 5
Ответ 4
По мере того, что было сделано, я не вижу симпатичного принтера, который по крайней мере имитирует вывод интерпретатора python с очень простым форматированием, поэтому my:
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[type(value) if type(value) in self.types else 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[type(value[key]) if type(value[key]) in self.types else 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[type(item) if type(item) in self.types else 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[type(item) if type(item) in self.types else 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[
type(value[key]) if type(value[key]) in self.types else 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 type(value) is dict:
items = [
nlch + repr(key) + ': ' + pretty(value[key], htchar, lfchar, indent + 1)
for key in value
]
return '{%s}' % (','.join(items) + lfchar + htchar * indent)
elif type(value) is list:
items = [
nlch + pretty(item, htchar, lfchar, indent + 1)
for item in value
]
return '[%s]' % (','.join(items) + lfchar + htchar * indent)
elif type(value) is 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'
}
По сравнению с другими версиями:
- Это решение напрямую ищет тип объекта, поэтому вы можете печатать почти все, а не только список или dict.
- Не имеет никакой зависимости.
- Все помещается внутри строки, поэтому вы можете делать с ней все, что хотите.
- Класс и функция были протестированы и работают с Python 2.7 и 3.4.
- Вы можете иметь все типы объектов внутри, это их представления, а не их содержимое, которое помещается в результат (так что строки имеют кавычки, строка Unicode полностью представлена ...).
- С версией класса вы можете добавить форматирование для каждого типа объекта, который вы хотите, или изменить его для уже определенных.
Клавиша
- может быть любого допустимого типа.
- Отступ и символ новой строки могут быть изменены для всего, что нам хотелось бы.
- Dict, List и Suples довольно печатаются.
Ответ 5
таким образом, вы можете распечатать его довольно хорошо, например, ваш словарь зовут Ясин
import json
print (json.dumps(yasin, indent=2))
Ответ 6
Еще один вариант с yapf
:
from pprint import pformat
from yapf.yapflib.yapf_api import FormatCode
dict_example = {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5], '4': {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5]}}
dict_string = pformat(dict_example)
formatted_code, _ = FormatCode(dict_string)
print(formatted_code)
Выход:
{
'1': '1',
'2': '2',
'3': [1, 2, 3, 4, 5],
'4': {
'1': '1',
'2': '2',
'3': [1, 2, 3, 4, 5]
}
}
Ответ 7
Как уже сообщали другие, вы можете использовать recursion/dfs для печати вложенных данных словаря и вызывать рекурсивно, если это словарь; в противном случае распечатайте данные.
def print_json(data):
if type(data) == dict:
for k, v in data.items():
print k
print_json(v)
else:
print data
Ответ 8
Я взял sth answer и немного изменил его, чтобы соответствовать моим потребностям вложенных словарей и списков:
def pretty(d, indent=0):
if isinstance(d, dict):
for key, value in d.iteritems():
print '\t' * indent + str(key)
if isinstance(value, dict) or isinstance(value, list):
pretty(value, indent+1)
else:
print '\t' * (indent+1) + str(value)
elif isinstance(d, list):
for item in d:
if isinstance(item, dict) or isinstance(item, list):
pretty(item, indent+1)
else:
print '\t' * (indent+1) + str(item)
else:
pass
Которая затем дает мне вывод, например:
>>>
xs:schema
@xmlns:xs
http://www.w3.org/2001/XMLSchema
xs:redefine
@schemaLocation
base.xsd
xs:complexType
@name
Extension
xs:complexContent
xs:restriction
@base
Extension
xs:sequence
xs:element
@name
Policy
@minOccurs
1
xs:complexType
xs:sequence
xs:element
...
Ответ 9
pout может напечатать что угодно, например, что вы кидаете (заимствуя data
из другого ответа):
data = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
pout.vs(data)
приведет к выводу на экран, например:
{
'a': 2,
'b':
{
'y':
{
't2': 5,
't1': 4
},
'x': 3
}
}
или вы можете вернуть форматированную строку вывода вашего объекта:
v = pout.s(data)
Его основной сценарий использования предназначен для отладки, поэтому он не задыхается от экземпляров объектов или чего-либо еще и обрабатывает вывод Unicode, как и следовало ожидать, работает в python 2.7 и 3.
Раскрытие: я автор и сопровождающий.
Ответ 10
Sth, я так рада;)
def pretty(d, indent=0):
for key, value in d.iteritems():
if isinstance(value, dict):
print '\t' * indent + (("%30s: {\n") % str(key).upper())
pretty(value, indent+1)
print '\t' * indent + ' ' * 32 + ('} # end of %s #\n' % str(key).upper())
elif isinstance(value, list):
for val in value:
print '\t' * indent + (("%30s: [\n") % str(key).upper())
pretty(val, indent+1)
print '\t' * indent + ' ' * 32 + ('] # end of %s #\n' % str(key).upper())
else:
print '\t' * indent + (("%30s: %s") % (str(key).upper(),str(value)))
Ответ 11
This class prints out a complex nested dictionary with sub dictionaries and sub lists.
##
## Recursive class to parse and print complex nested dictionary
##
class NestedDictionary(object):
def __init__(self,value):
self.value=value
def print(self,depth):
spacer="--------------------"
if type(self.value)==type(dict()):
for kk, vv in self.value.items():
if (type(vv)==type(dict())):
print(spacer[:depth],kk)
vvv=(NestedDictionary(vv))
depth=depth+3
vvv.print(depth)
depth=depth-3
else:
if (type(vv)==type(list())):
for i in vv:
vvv=(NestedDictionary(i))
depth=depth+3
vvv.print(depth)
depth=depth-3
else:
print(spacer[:depth],kk,vv)
##
## Instatiate and execute - this prints complex nested dictionaries
## with sub dictionaries and sub lists
## 'something' is a complex nested dictionary
MyNest=NestedDictionary(weather_com_result)
MyNest.print(0)
Ответ 12
Я написал этот простой код для печати общей структуры объекта json в Python.
def getstructure(data, tab = 0):
if type(data) is dict:
print ' '*tab + '{'
for key in data:
print ' '*tab + ' ' + key + ':'
getstructure(data[key], tab+4)
print ' '*tab + '}'
elif type(data) is list and len(data) > 0:
print ' '*tab + '['
getstructure(data[0], tab+4)
print ' '*tab + ' ...'
print ' '*tab + ']'
результат для следующих данных
a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':'p','unicode':u'\xa7',("tuple","key"):"valid"}
getstructure(a)
очень компактен и выглядит следующим образом:
{
function:
tuple:
list:
[
...
]
dict:
{
a:
2:
}
unicode:
('tuple', 'key'):
}
Ответ 13
От эта ссылка:
def prnDict(aDict, br='\n', html=0,
keyAlign='l', sortKey=0,
keyPrefix='', keySuffix='',
valuePrefix='', valueSuffix='',
leftMargin=0, indent=1 ):
'''
return a string representive of aDict in the following format:
{
key1: value1,
key2: value2,
...
}
Spaces will be added to the keys to make them have same width.
sortKey: set to 1 if want keys sorted;
keyAlign: either 'l' or 'r', for left, right align, respectively.
keyPrefix, keySuffix, valuePrefix, valueSuffix: The prefix and
suffix to wrap the keys or values. Good for formatting them
for html document(for example, keyPrefix='<b>', keySuffix='</b>').
Note: The keys will be padded with spaces to have them
equally-wide. The pre- and suffix will be added OUTSIDE
the entire width.
html: if set to 1, all spaces will be replaced with ' ', and
the entire output will be wrapped with '<code>' and '</code>'.
br: determine the carriage return. If html, it is suggested to set
br to '<br>'. If you want the html source code eazy to read,
set br to '<br>\n'
version: 04b52
author : Runsun Pan
require: odict() # an ordered dict, if you want the keys sorted.
Dave Benjamin
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/161403
'''
if aDict:
#------------------------------ sort key
if sortKey:
dic = aDict.copy()
keys = dic.keys()
keys.sort()
aDict = odict()
for k in keys:
aDict[k] = dic[k]
#------------------- wrap keys with ' ' (quotes) if str
tmp = ['{']
ks = [type(x)==str and "'%s'"%x or x for x in aDict.keys()]
#------------------- wrap values with ' ' (quotes) if str
vs = [type(x)==str and "'%s'"%x or x for x in aDict.values()]
maxKeyLen = max([len(str(x)) for x in ks])
for i in range(len(ks)):
#-------------------------- Adjust key width
k = {1 : str(ks[i]).ljust(maxKeyLen),
keyAlign=='r': str(ks[i]).rjust(maxKeyLen) }[1]
v = vs[i]
tmp.append(' '* indent+ '%s%s%s:%s%s%s,' %(
keyPrefix, k, keySuffix,
valuePrefix,v,valueSuffix))
tmp[-1] = tmp[-1][:-1] # remove the ',' in the last item
tmp.append('}')
if leftMargin:
tmp = [ ' '*leftMargin + x for x in tmp ]
if html:
return '<code>%s</code>' %br.join(tmp).replace(' ',' ')
else:
return br.join(tmp)
else:
return '{}'
'''
Example:
>>> a={'C': 2, 'B': 1, 'E': 4, (3, 5): 0}
>>> print prnDict(a)
{
'C' :2,
'B' :1,
'E' :4,
(3, 5):0
}
>>> print prnDict(a, sortKey=1)
{
'B' :1,
'C' :2,
'E' :4,
(3, 5):0
}
>>> print prnDict(a, keyPrefix="<b>", keySuffix="</b>")
{
<b>'C' </b>:2,
<b>'B' </b>:1,
<b>'E' </b>:4,
<b>(3, 5)</b>:0
}
>>> print prnDict(a, html=1)
<code>{
'C' :2,
'B' :1,
'E' :4,
(3, 5):0
}</code>
>>> b={'car': [6, 6, 12], 'about': [15, 9, 6], 'bookKeeper': [9, 9, 15]}
>>> print prnDict(b, sortKey=1)
{
'about' :[15, 9, 6],
'bookKeeper':[9, 9, 15],
'car' :[6, 6, 12]
}
>>> print prnDict(b, keyAlign="r")
{
'car':[6, 6, 12],
'about':[15, 9, 6],
'bookKeeper':[9, 9, 15]
}
'''
Ответ 14
Здесь что-то, что напечатает любой тип вложенного словаря, при этом отслеживая "родительские" словари на этом пути.
dicList = list()
def prettierPrint(dic, dicList):
count = 0
for key, value in dic.iteritems():
count+=1
if str(value) == 'OrderedDict()':
value = None
if not isinstance(value, dict):
print str(key) + ": " + str(value)
print str(key) + ' was found in the following path:',
print dicList
print '\n'
elif isinstance(value, dict):
dicList.append(key)
prettierPrint(value, dicList)
if dicList:
if count == len(dic):
dicList.pop()
count = 0
prettierPrint(dicExample, dicList)
Это хорошая отправная точка для печати в соответствии с различными форматами, например, указанными в OP. Все, что вам действительно нужно сделать, это операции вокруг блоков печати. Обратите внимание, что он видит, стоит ли значение "OrderedDict()". В зависимости от того, используете ли вы что-то из Contater datatypes Collections, вы должны сделать такие отказоустойчивые блоки, чтобы блок elif не видел его в качестве дополнительного словаря из-за его имени. На данный момент примерный словарь, например
example_dict = {'key1': 'value1',
'key2': 'value2',
'key3': {'key3a': 'value3a'},
'key4': {'key4a': {'key4aa': 'value4aa',
'key4ab': 'value4ab',
'key4ac': 'value4ac'},
'key4b': 'value4b'}
напечатает
key3a: value3a
key3a was found in the following path: ['key3']
key2: value2
key2 was found in the following path: []
key1: value1
key1 was found in the following path: []
key4ab: value4ab
key4ab was found in the following path: ['key4', 'key4a']
key4ac: value4ac
key4ac was found in the following path: ['key4', 'key4a']
key4aa: value4aa
key4aa was found in the following path: ['key4', 'key4a']
key4b: value4b
key4b was found in the following path: ['key4']
~ изменяющий код для соответствия формату вопроса ~
lastDict = list()
dicList = list()
def prettierPrint(dic, dicList):
global lastDict
count = 0
for key, value in dic.iteritems():
count+=1
if str(value) == 'OrderedDict()':
value = None
if not isinstance(value, dict):
if lastDict == dicList:
sameParents = True
else:
sameParents = False
if dicList and sameParents is not True:
spacing = ' ' * len(str(dicList))
print dicList
print spacing,
print str(value)
if dicList and sameParents is True:
print spacing,
print str(value)
lastDict = list(dicList)
elif isinstance(value, dict):
dicList.append(key)
prettierPrint(value, dicList)
if dicList:
if count == len(dic):
dicList.pop()
count = 0
Используя тот же примерный код, он напечатает следующее:
['key3']
value3a
['key4', 'key4a']
value4ab
value4ac
value4aa
['key4']
value4b
Это не совсем то, что запрашивается в OP. Разница заключается в том, что родительский ^ n все еще печатается, вместо того, чтобы отсутствовать и заменяется пробелом. Чтобы добраться до формата OP, вам нужно сделать что-то вроде следующего: итеративно сравнить dicList с lastDict. Вы можете сделать это, создав новый словарь и скопировав на него содержимое dicList, проверяя, является ли я в скопированном словаре таким же, как я в lastDict, и - если это так - записывает пробел в эту позицию i, используя функцию умножения строк.
Ответ 15
Я просто возвращаюсь к этому вопросу после принятия sth ответа и внесения небольшой, но очень полезной модификации. Эта функция печатает все ключи в дереве JSON, а также размер листовых узлов в этом дереве.
def print_JSON_tree(d, indent=0):
for key, value in d.iteritems():
print ' ' * indent + unicode(key),
if isinstance(value, dict):
print; print_JSON_tree(value, indent+1)
else:
print ":", str(type(d[key])).split("'")[1], "-", str(len(unicode(d[key])))
Это действительно приятно, когда у вас есть большие объекты JSON и вы хотите выяснить, где находится мясо. Пример:
>>> print_JSON_tree(JSON_object)
key1
value1 : int - 5
value2 : str - 16
key2
value1 : str - 34
value2 : list - 5623456
Это скажет вам, что большинство данных, о которых вы заботитесь, вероятно, находятся внутри JSON_object['key1']['key2']['value2']
, потому что длина этого значения, отформатированного как строка, очень велика.
Ответ 16
Используйте эту функцию:
def pretty_dict(d, n=1):
for k in d:
print(" "*n + k)
try:
pretty_dict(d[k], n=n+4)
except TypeError:
continue
Назовите это так:
pretty_dict(mydict)
Ответ 17
Я тоже являюсь родственным новичком-питоном, но за последние пару недель я работал с вложенными словарями, и это то, что я придумал.
Вам следует попробовать использовать стек. Сделайте ключи из корневого словаря в список списка:
stack = [ root.keys() ] # Result: [ [root keys] ]
Переходя в обратном порядке от последнего к первому, найдите каждый ключ в словаре, чтобы узнать, является ли его значение (также) словарем. Если нет, распечатайте ключ и удалите его. Однако, если значение для ключа является словарем, распечатайте ключ, затем добавьте ключи для этого значения в конец стека и начните обработку этого списка таким же образом, повторяя рекурсивно для каждого нового списка ключей.
Если значение для второго ключа в каждом списке было в словаре, у вас было бы что-то вроде этого после нескольких раундов:
[['key 1','key 2'],['key 2.1','key 2.2'],['key 2.2.1','key 2.2.2'],[`etc.`]]
Подход к этому подходу заключается в том, что отступ всего \t
раз превышает длину стека:
indent = "\t" * len(stack)
Недостатком является то, что для проверки каждой клавиши вам нужно перейти к соответствующему подъязыкам словаря, хотя это можно легко справиться с пониманием списка и простым циклом for
:
path = [li[-1] for li in stack]
# The last key of every list of keys in the stack
sub = root
for p in path:
sub = sub[p]
if type(sub) == dict:
stack.append(sub.keys()) # And so on
Имейте в виду, что для этого подхода вам потребуется очистить конечные пустые списки и удалить последний ключ в любом списке, за которым следует пустой список (который, конечно же, может создать еще один пустой список и т.д.).
Существуют и другие способы реализации этого подхода, но, надеюсь, это дает вам общее представление о том, как это сделать.
EDIT: если вы не хотите проходить все это, модуль pprint
печатает вложенные словари в хорошем формате.
Ответ 18
Здесь функция, которую я написал, основываясь на том, что комментарий. Он работает так же, как json.dumps с отступом, но я использую вкладки вместо пространства для отступов. В Python 3.2+ вы можете указать отступ как "\ t" напрямую, но не в 2.7.
def pretty_dict(d):
def pretty(d, indent):
for i, (key, value) in enumerate(d.iteritems()):
if isinstance(value, dict):
print '{0}"{1}": {{'.format( '\t' * indent, str(key))
pretty(value, indent+1)
if i == len(d)-1:
print '{0}}}'.format( '\t' * indent)
else:
print '{0}}},'.format( '\t' * indent)
else:
if i == len(d)-1:
print '{0}"{1}": "{2}"'.format( '\t' * indent, str(key), value)
else:
print '{0}"{1}": "{2}",'.format( '\t' * indent, str(key), value)
print '{'
pretty(d,indent=1)
print '}'
Пример:
>>> dict_var = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
>>> pretty_dict(dict_var)
{
"a": "2",
"b": {
"y": {
"t2": "5",
"t1": "4"
},
"x": "3"
}
}