Как красиво распечатать вложенные словари?

289

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

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

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

key1
    value1
    value2
    key2
       value1
       value2

и т.п.

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

Мартино
источник
29
Что значит "не работал"? Пожалуйста, укажите очень точно, как pprint "не работал".
С.Лотт
5
Теперь я использовал 3 из этих ответов (каждый из которых хорош в определенном сценарии): @ Ответ json Кена хорош, но иногда дает сбой, когда объект не может быть сериализуемым json (выдает исключение). если @ json-ответ Кена не работает, попробуйте @ yaml-ответ Энди, и он должен сработать, но вывод строки немного менее понятен для человека. [@ sth's answer] является наиболее общим (должен работать для любого объекта и не использовать библиотеки).
Тревор Бойд Смит

Ответы:

143

Я не уверен, как именно вы хотите, чтобы форматирование выглядело, но вы могли бы начать с такой функции:

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))
STH
источник
8
Знаешь, обычный ответ Кена намного лучше, чем этот. Json уже обрабатывает все, и это может привести к таким ошибкам: UnicodeEncodeError: кодек «ascii» не может кодировать символ u '\ xf3' в позиции 50: порядковый номер не в диапазоне (128)
чудо,
Я не могу заставить его работать с вложенным dict моего решения, потому что он дал мне UnicodeEncodeError, также он не печатает ключ dict, не заходит в список и кортежи и не поддерживает допустимый синтаксис python.
y.petremann
Этот ответ для меня сработал, но я разместил новый вопрос stackoverflow.com/questions/36972225/…, который устанавливает ограничение на количество значений, которые должны быть напечатаны.
gsamaras
Довольно хорошо. Если у вас есть вложенные списки, как в вопросе OP, вам нужно добавить некоторую обработку для этого. Если у вас есть проблемы с Py2, это потому, что он не может правильно обрабатывать Unicode без таких хаков, как __future__этот ответ теперь упоминает, поэтому вы должны использовать их там, где это необходимо (или обновить до 3).
Судо
Это работало достаточно хорошо для меня: python def pretty(d, indent=0): for key, value in d.items(): if isinstance(value, dict): print(' ' * indent + str(key)) pretty(value, indent+1) else: print(' ' * (indent+1) + f"{key}: {value}")
hum3
500

Моей первой мыслью было, что сериализатор 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
        }
    }
}
кругозор
источник
41
Это круто, но плохо печатает все словари. печать json.dumps (MyObject .__ dict__, sort_keys = True, отступы = 4) #TypeError: <объект в 0x0000000002E6A748> не JSON сериализации
tponthieux
4
Хотя это выглядит полезным, его вывод - не то, что хотел ОП.
Мартино
2
@martineau: Запрошенный вывод OP не имеет смысла, словарям нужны ключи для каждого значения.
naught101
2
@ naught101: симпатичный принтер может делать все, что нужно для получения желаемого результата.
Мартино
22
json.dumps принимает функцию преобразования в качестве необязательного аргумента, поэтому с помощью json.dumps (myObject .__ dict__, sort_keys = True, indent = 4, deault = str) вы можете по крайней мере использовать реализацию объектов repr, чтобы напечатать себя и обойти 'не JSON-сериализуемая'
ошибка
56

Вы можете попробовать YAML через PyYAML . Его выход может быть точно настроен. Я бы предложил начать со следующего:

print yaml.dump(data, allow_unicode=True, default_flow_style=False)

Результат очень читабелен; при необходимости его также можно проанализировать обратно в Python.

Редактировать:

Пример:

>>> 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
Энди Михайленко
источник
1
Использование yaml очень интересно, потому что оно сохраняет тип данных поверх его формата, единственное, что я могу сказать против этого, это то, что он не генерирует допустимую строку python, но почти может быть преобразован обратно в python.
y.petremann
1
yaml не нравится версия скалярных типов Numpy ... Меня не удивило то, что она не поддерживает numpy массивы, но я бы ожидал одинакового вывода для a floatи anumpy.float64
PhilMacKay
этот подход также работал для меня, используя список словарей
Грант Шеннон
36

Что касается того, что было сделано, я не вижу симпатичного принтера, который по крайней мере имитирует вывод интерпретатора 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[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'
}

По сравнению с другими версиями:

  • Это решение напрямую ищет тип объекта, поэтому вы можете напечатать практически все, не только список или диктовку.
  • Не имеет никакой зависимости.
  • Все помещено в строку, поэтому вы можете делать с ней все, что захотите.
  • Класс и функция были протестированы и работают с Python 2.7 и 3.4.
  • Вы можете иметь все типы объектов внутри, это их представления, а не их содержимое, которое помещается в результат (поэтому строка имеет кавычки, строка Unicode полностью представлена ​​...).
  • С версией класса вы можете добавить форматирование для каждого типа объекта или изменить их на уже определенные.
  • ключ может быть любого допустимого типа.
  • Отступы и символы новой строки могут быть изменены для всего, что мы хотели.
  • Dict, List и Tuples довольно напечатаны.
y.petremann
источник
2
Это определенно должно быть принятым решением - отсутствие зависимости от JSON огромно.
Джош
было бы здорово, если бы он мог делать объекты, конвертируя их в диктанты и устанавливая их ключ в качестве типа объекта
Alex Cory
Вы можете в основном заменить метод format_object внутри или снаружи, чтобы сделать это.
y.petremann
set_formater - нужно два т, это опечатка, должно быть форматер
Николай Прокопьев
32

таким образом, вы можете распечатать его довольно хорошо, например, ваш словарь зовут Ясин

import json

print (json.dumps(yasin, indent=2))
Ясин Лачини
источник
5
Это предполагает, что содержимое словаря является json serialize-способным, что не всегда верно.
SpiXel
8

Еще один вариант с 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]
    }
}
Эяль Левин
источник
6

Один из самых питонских способов для этого - использовать уже собранный модуль pprint .

Аргумент, который вам нужен для определения глубины печати, такой, какой вы можете ожидать depth

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

Это оно !

Хуан-Kabbali
источник
5

Как уже сообщали другие, вы можете использовать recursion / dfs для печати вложенных данных словаря и вызывать рекурсивно, если это словарь; в противном случае распечатайте данные.

def print_json(data):
    if type(data) == dict:
            for k, v in data.items():
                    print k
                    print_json(v)
    else:
            print data
Рохит Малгаонкар
источник
5

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.

Раскрытие : я автор и сопровождающий.

Jaymon
источник
3

Я взял ответ sth и слегка изменил его, чтобы он соответствовал моим потребностям во вложенных словарях и списках:

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
                                            ...
Джейми Иванов
источник
1

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)))
ВИНДЕКС
источник
1
-1: не обрабатывает listзначения, которые не являются dictэкземплярами, т.е. pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Мне тоже не нравятся прописные клавиши.
Мартино
Ваше решение предполагает, что внутри списка не может быть слова dict. Также считается, что мы не хотим печатать список или кортеж. Наконец, не используйте заглавные буквы, результат для {'a': 0, 'A': 1} будет неверным.
y.petremann
1
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)
Боб Локвуд
источник
1

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

Я сам относительный новичок в 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модуль печатает вложенные словари в хорошем формате.

danwroy
источник
0

Вот функция, которую я написал на основе комментариев. Он работает так же, как 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"
    }
}
Аль Конрад
источник
Я не могу заставить его работать с вложенным указанием моего решения, потому что оно дало мне UnicodeEncodeError, а также элементы и ключи все конвертируются в строки, что если мы используем числа или кортежи, которые содержат списки и слова? В конце концов, ваше решение должно учитывать, что наш объект, который мы хотим напечатать, должен быть диктатом.
y.petremann
Я не пытался написать универсальную функцию печати для python dict. Самые рейтинговые комментарии уже демонстрируют, как правильно печатать диктовку. Мой вклад заключался в написании альтернативы json.dumps с '\ t' для отступа вместо вкладок в python 2.7.
Аль Конрад
Я согласен с вами по поводу написания альтернативы json.dumps, для меня те же проблемы, что и для json.dumps. Кроме того, вы можете использовать простое регулярное выражение для изменения типа отступа, что делает ваш код проще.
y.petremann
0

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

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 с помощью функции умножения строк. ,

Gavin
источник
0

По этой ссылке :

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]
}
'''
user2757572
источник
0

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

Используйте эту функцию:

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)
fiftytwocards
источник
Это не работает, если значения являются строками. Он печатает каждый символ строки на новой строке, но кажется, что клавиши работают нормально.
Энтони
0

Вот что я придумал, работая над классом, который должен был написать словарь в .txt файле:

@staticmethod
def _pretty_write_dict(dictionary):

    def _nested(obj, level=1):
        indentation_values = "\t" * level
        indentation_braces = "\t" * (level - 1)
        if isinstance(obj, dict):
            return "{\n%(body)s%(indent_braces)s}" % {
                "body": "".join("%(indent_values)s\'%(key)s\': %(value)s,\n" % {
                    "key": str(key),
                    "value": _nested(value, level + 1),
                    "indent_values": indentation_values
                } for key, value in obj.items()),
                "indent_braces": indentation_braces
            }
        if isinstance(obj, list):
            return "[\n%(body)s\n%(indent_braces)s]" % {
                "body": "".join("%(indent_values)s%(value)s,\n" % {
                    "value": _nested(value, level + 1),
                    "indent_values": indentation_values
                } for value in obj),
                "indent_braces": indentation_braces
            }
        else:
            return "\'%(value)s\'" % {"value": str(obj)}

    dict_text = _nested(dictionary)
    return dict_text

Теперь, если у нас есть такой словарь:

some_dict = {'default': {'ENGINE': [1, 2, 3, {'some_key': {'some_other_key': 'some_value'}}], 'NAME': 'some_db_name', 'PORT': '', 'HOST': 'localhost', 'USER': 'some_user_name', 'PASSWORD': 'some_password', 'OPTIONS': {'init_command': 'SET foreign_key_checks = 0;'}}}

И мы делаем:

print(_pretty_write_dict(some_dict))

Мы получили:

{
    'default': {
        'ENGINE': [
            '1',
            '2',
            '3',
            {
                'some_key': {
                    'some_other_key': 'some_value',
                },
            },
        ],
        'NAME': 'some_db_name',
        'OPTIONS': {
            'init_command': 'SET foreign_key_checks = 0;',
        },
        'HOST': 'localhost',
        'USER': 'some_user_name',
        'PASSWORD': 'some_password',
        'PORT': '',
    },
}
Эдгардо Обрегон
источник