Як красиво друкувати вкладені словники?


289

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

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

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

key1
    value1
    value2
    key2
       value1
       value2

тощо.

Як я можу це зробити?


29
Що означає "не працювало"? Вкажіть, будь ласка, дуже точно, як pprint "не працював".
S.Lott

5
Зараз я використав 3 з цих відповідей (кожен хороший за певним сценарієм): @ Кен json відповідь хороший, але інколи виходить з ладу, коли об'єкт не може бути серіалізаційним json (викиди винятку). якщо @ Кен відповідь json не працює, спробуйте відповідь на yaml @ Енді, і він повинен працювати, але вихідний рядок трохи легше для читання. [@ sth відповідь] є найбільш загальним (повинен працювати для будь-якого об'єкта і не використовувати жодних ліб).
Тревор Бойд Сміт

Відповіді:


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))

8
Ви знаєте, @ звичайна відповідь Кена набагато краща за це. Json вже обробляє все, і це може призвести до таких помилок: UnicodeEncodeError: 'ascii' кодек не може кодувати символ u '\ xf3' у позиції 50: порядковий не в діапазоні (128)
дивно чому

Я не можу змусити його працювати з вкладеним диктом мого рішення, тому що він дав мені UnicodeEncodeError, також він не друкує ключ dict, не заходить у список та кортежі і не зберігає синтаксис дійсного python.
y.petremann

Ця відповідь спрацювала як принада для мене, проте я розмістив нове запитання stackoverflow.com/questions/36972225/…, яке встановлює обмеження на кількість значень, які слід надрукувати.
gsamaras

Досить добре. Якщо у вас є вкладені списки, як у запитанні про ОП, вам потрібно додати певну обробку для цього. Якщо у вас є проблеми в 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: Симпатичний принтер може робити все необхідне, щоб отримати бажаний вихід.
martineau

22
json.dumps приймає функцію перетворення як необов'язковий аргумент, тому за допомогою json.dumps (myObject .__ dict__, sort_keys = True, відступ = 4, deault = str) ви можете принаймні використовувати об'єкти реалізації repr, щоб надрукувати себе і обійти 'не JSON серіалізаційний' TypeError
RFairey

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 ... Я не здивувався, що це не підтримує нумерові масиви, але я б очікував того ж виходу для 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 досить надруковані.

2
Це безумовно повинно бути прийнятим рішенням - відсутність залежності від JSON величезна.
Джош

було б здорово, якби він міг робити об’єкти, перетворюючи їх на дикти і встановлюючи їх ключ на тип об’єкта
Алекс Кори

Ви можете в основному замінити метод format_object внутрішньо або зовнішньо, щоб це зробити.
y.petremann

set_formater - потрібно два т, це друкарня, має бути форматування
Микола Прокоп'єв

32

таким чином ви можете надрукувати його досить способом, наприклад, зразок вашого словника - yasin

import json

print (json.dumps(yasin, indent=2))

5
Це передбачає, що зміст словника може бути serialize-json, що обов'язково не відповідає дійсності.
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]
    }
}

5

Як опублікували інші, ви можете використовувати рекурсію / dfs для друку вкладених даних словника та рекурсивно дзвонити, якщо це словник; в іншому випадку надрукуйте дані.

def print_json(data):
    if type(data) == dict:
            for k, v in data.items():
                    print k
                    print_json(v)
    else:
            print data

5

Один з найбільш пітонічних способів цього - використовувати вже побудований модуль pprint .

Аргумент, необхідний для визначення глибини друку, - це, як ви можете, очікувати depth

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

Це воно !


4

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.

оприлюднення : я автор та підтримувач pout.


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'. Мені також не подобаються це великі клавіші.
martineau

Ваше рішення вважає, що всередині списку всередині кореневого дікта не може бути дикту. Крім того, він вважає, що ми не хочемо доситьдрукувати список або кортеж. Зрештою, не використовуйте великі літери, результат для {'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

Я сам родич пітона, але останні кілька тижнів працюю з вкладеними словниками, і ось що я придумав.

Спробуйте скористатися стеком. Складіть клавіші з кореневого словника в список списку:

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модуль друкує вкладені словники у приємному форматі.


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. Найвищі рейтинги коментарів уже демонструють, як красиво надрукувати випуск. Мій внесок полягав у тому, щоб написати альтернативу 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)

Це хороша відправна точка для друку у різних форматах, як у визначеному в ОП. Все, що вам потрібно зробити - це операції навколо блоків друку . Зауважте, що схоже на те, чи є значення "OrdersDict ()". Залежно від того, використовуєте ви щось із колекцій типів даних контейнерів , вам слід зробити такі збої відмов, щоб блок 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

Це не зовсім те , що запитується в ОП. Різниця полягає в тому, що батьківський ^ n як і раніше друкується, замість того, щоб він не був замінений на пробіл. Щоб перейти до формату OP, вам потрібно зробити щось на кшталт наступного: ітеративно порівняти dicList з останнімDict . Ви можете зробити це, створивши новий словник і скопіювавши до нього вміст dicList, перевіривши, чи є я у скопійованому словнику таким самим, як i в lastDict, і - якщо він є - записати пробіл у цей я позицію за допомогою функції мультиплікатора рядків .


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]
}
'''

0

Я просто повертаюся до цього питання після того, як прийняв відповідь 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

Використовуйте цю функцію:

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)

Це не працює, якщо значення є рядками. Він друкує кожен символ рядка в новому рядку, але клавіші, здається, працюють нормально.
Ентоні

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': '',
    },
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.