Как красиво распечатать вложенные словари? - PullRequest
225 голосов
/ 12 июля 2010

Как я могу довольно напечатать словарь с глубиной ~ 4 в Python? Я попробовал красивую печать с pprint(), но это не сработало:

import pprint 
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)

Я просто хочу отступ ("\t") для каждого вложения, чтобы я получил что-то вроде этого:

key1
    value1
    value2
    key2
       value1
       value2

и т.д..

Как я могу это сделать?

Ответы [ 17 ]

1 голос
/ 01 января 2016

Я написал этот простой код для печати общей структуры объекта 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'):
}
1 голос
/ 21 ноября 2012

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)))
0 голосов
/ 30 августа 2017

Я просто возвращаюсь к этому вопросу после того, как взял ответ 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'], поскольку длина этого значения, отформатированного в виде строки, очень велика.

0 голосов
/ 26 марта 2014

Вот функция, которую я написал на основе комментариев.Он работает так же, как 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"
    }
}
0 голосов
/ 20 июля 2016

Вот кое-что, что напечатает любой вложенный словарь, отслеживая при этом «родительские» словари.

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.Все, что вам действительно нужно, это операции с блоками Print .Обратите внимание, что он проверяет, является ли значение OrderedDict ().В зависимости от того, используете ли вы что-либо из коллекций типов данных контейнеров , вы должны делать такие отказоустойчивые, чтобы блок 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, проверив, совпадает ли i в скопированном словаре с i в lastDict, и - если это -- запись пробелов в эту позицию i с использованием функции умножения строк.

0 голосов
/ 01 марта 2015

С по этой ссылке :

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 '&nbsp;', 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(' ','&nbsp;')
        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>{
&nbsp;'C'&nbsp;&nbsp;&nbsp;:2,
&nbsp;'B'&nbsp;&nbsp;&nbsp;:1,
&nbsp;'E'&nbsp;&nbsp;&nbsp;:4,
&nbsp;(3,&nbsp;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]
}
'''
0 голосов
/ 22 июля 2010

Я сам относительный новичок в Python, но последние пару недель я работал с вложенными словарями, и это то, что я придумал.

Вы должны попробовать использовать стек. Превратить ключи из корневого словаря в список из списка:

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

Имейте в виду, что этот подход потребует очистки конечных пустых списков, и для удаления последнего ключа в любом списке, за которым следует пустой список (что, конечно, может создать другой пустой список и т. Д. ).

Существуют и другие способы реализации этого подхода, но, надеюсь, это даст вам базовое представление о том, как это сделать.

РЕДАКТИРОВАТЬ: Если вы не хотите проходить через все это, модуль pprint печатает вложенные словари в хорошем формате.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...