Jak ładnie wydrukować zagnieżdżone słowniki?


289

Jak mogę ładnie wydrukować słownik o głębokości ~ 4 w Pythonie? Próbowałem ładnego drukowania pprint(), ale to nie działało:

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

Chcę po prostu wcięcia ( "\t") dla każdego zagnieżdżenia, aby uzyskać coś takiego:

key1
    value1
    value2
    key2
       value1
       value2

itp.

W jaki sposób mogę to zrobić?


29
Co znaczy „nie działało”? Proszę bardzo dokładnie określić, w jaki sposób pprint „nie działał”.
S.Lott,

5
Użyłem teraz 3 z tych odpowiedzi (każde dobro w konkretnym scenariuszu): @ Odpowiedź Jsona Kena jest dobra, ale czasami kończy się niepowodzeniem, gdy obiekt nie może być serializowany jsonem (generuje wyjątek). jeśli odpowiedź Jsona @ Kena nie działa, wypróbuj yamlową odpowiedź @ Andy'ego i powinna ona działać, ale ciąg znaków jest nieco mniej czytelny dla człowieka. [Odpowiedź @ sth] jest najbardziej ogólna (powinna działać dla każdego obiektu i nie używa żadnych bibliotek).
Trevor Boyd Smith

Odpowiedzi:


143

Nie jestem pewien, jak dokładnie powinno wyglądać formatowanie, ale możesz zacząć od takiej funkcji:

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
Wiesz, że konwencjonalna odpowiedź @ Kena jest znacznie lepsza. Json już wszystko obsługuje, a to może dawać błędy, takie jak: UnicodeEncodeError: kodek „ascii” nie może zakodować znaku u '\ xf3' na pozycji 50: numer porządkowy poza zakresem (128)
zastanawia się

Nie mogę sprawić, by działało z zagnieżdżonym dict mojego rozwiązania, ponieważ dało mi to błąd UnicodeEncodeError, nie drukuje też klucza dict, nie wchodzi do listy i krotek i nie utrzymuje poprawnej składni Pythona.
y.petremann

Ta odpowiedź zadziałała dla mnie jak urok, jednak opublikowałem nowe pytanie stackoverflow.com/questions/36972225/..., które określa limit liczby drukowanych wartości.
gsamaras

Całkiem dobre. Jeśli masz zagnieżdżone listy jak w pytaniu PO, musisz do tego dodać trochę obsługi. Jeśli masz problemy z Py2, to dlatego, że nie potrafi poprawnie obsługiwać Unicode bez takich hacków __future__, teraz wspomniana odpowiedź, więc musisz zatrudnić te tam, gdzie są potrzebne (lub zaktualizować już do 3).
sudo

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}")
Działa to

500

Moją pierwszą myślą było to, że serializator JSON jest prawdopodobnie całkiem dobry w zagnieżdżonych słownikach, więc oszukiwałbym i używał tego:

>>> 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
To jest fajne, ale nie drukuje dobrze wszystkich słowników. print json.dumps (myObject .__ dict__, sort_keys = True, wcięcie = 4) #TypeError: <obiekt o wartości 0x0000000002E6A748> nie jest serializowany JSON
tponthieux

4
Chociaż wygląda to na użyteczne, jego wynik nie jest tym, czego chciał PO.
martineau

2
@martineau: Żądane dane wyjściowe OP nie mają sensu, słowniki potrzebują kluczy według wartości.
naught101

2
@ naught101: Ładna drukarka może zrobić wszystko, co jest potrzebne do uzyskania pożądanego rezultatu.
martineau,

22
json.dumps przyjmuje funkcję konwersji jako opcjonalny argument, więc z json.dumps (myObject .__ dict__, sort_keys = True, wcięcie = 4, deault = str) możesz przynajmniej użyć implementacji obiektowej repr, aby wydrukować się i obejść błąd typu „no JSON serializable”
RFairey

56

Możesz spróbować YAML przez PyYAML . Jego wydajność można precyzyjnie dostroić. Proponuję zacząć od następującego:

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

Wynik jest bardzo czytelny; w razie potrzeby można go również przeanalizować z powrotem do Pythona.

Edytować:

Przykład:

>>> 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
Używanie yaml jest bardzo interesujące, ponieważ utrzymuje typ danych w swoim formacie, jedyną rzeczą, którą mogę przeciw temu powiedzieć, jest to, że nie generuje prawidłowego ciągu python, ale prawie można go przekonwertować z powrotem w python.
y.petremann

1
yaml nie lubi wersji typów skalarnych Numpy ... Nie byłem zaskoczony, że nie obsługuje tablic numpy, ale oczekiwałbym tego samego wyjścia dla a floati anumpy.float64
PhilMacKay

takie podejście zadziałało również dla mnie przy użyciu listy słowników
Grant Shannon

36

Co do tego, co zostało zrobione, nie widzę żadnej ładnej drukarki, która przynajmniej naśladuje wyjście interpretera Pythona z bardzo prostym formatowaniem, więc oto moje:

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)

Aby zainicjować:

pretty = Formatter()

Może obsługiwać dodawanie formatererów dla zdefiniowanych typów, wystarczy utworzyć funkcję dla takiej jak ta i powiązać ją z wybranym typem za pomocą 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)

Ze względów historycznych zachowuję poprzednią ładną drukarkę, która była funkcją zamiast klasy, ale oba mogą być używane w ten sam sposób, wersja klasowa po prostu pozwala na znacznie więcej:

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)

Aby go użyć:

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

W porównaniu do innych wersji:

  • To rozwiązanie szuka bezpośrednio typu obiektu, więc możesz wydrukować prawie wszystko, nie tylko listę lub dyktowanie.
  • Nie ma żadnej zależności.
  • Wszystko jest umieszczone w sznurku, dzięki czemu możesz robić z nim, co chcesz.
  • Klasa i funkcja zostały przetestowane i współpracują z Pythonem 2.7 i 3.4.
  • Możesz mieć wszystkie typy obiektów w środku, to ich reprezentacje, a nie ich zawartość, która jest umieszczana w wyniku (więc ciąg znaków ma cudzysłowy, ciąg znaków Unicode jest w pełni reprezentowany ...).
  • W wersji klasowej możesz dodawać formatowanie dla każdego typu obiektu, który chcesz, lub zmieniać je dla już zdefiniowanych.
  • klucz może być dowolnego poprawnego typu.
  • Wcięcie i znak nowej linii można zmienić na wszystko, co chcemy.
  • Dict, List i Tuples są dość drukowane.

2
To zdecydowanie powinno być przyjęte rozwiązanie - brak zależności od JSON jest ogromny.
Josh

byłoby fajnie, gdyby mógł robić obiekty, konwertując je na dyktanda i ustawiając ich klucz na typ obiektu
Alex Cory

W tym celu możesz w zasadzie zastąpić metodę format_object wewnętrznie lub zewnętrznie.
y.petremann

set_formater - potrzebujesz dwóch t, ​​to jest literówka, powinien być formatyzator
Nikolay Prokopyev

32

w ten sposób możesz wydrukować go w ładny sposób, na przykład nazwa twojego słownika to yasin

import json

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

5
Zakłada się, że zawartość słownika jest możliwa do serializacji w jsonie, co niekoniecznie jest prawdą.
SpiXel,

8

Inna opcja z 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)

Wynik:

{
    '1': '1',
    '2': '2',
    '3': [1, 2, 3, 4, 5],
    '4': {
        '1': '1',
        '2': '2',
        '3': [1, 2, 3, 4, 5]
    }
}

5

Jak napisali inni, możesz użyć rekurencji / dfs, aby wydrukować dane zagnieżdżonego słownika i wywołać rekurencyjnie, jeśli jest to słownik; w przeciwnym razie wydrukuj dane.

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

5

Jednym z najbardziej pythonicznych sposobów jest użycie już zbudowanego modułu pprint .

Argument potrzebny do zdefiniowania głębokości drukowania jest taki, jak można się spodziewać depth

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

Otóż ​​to !


4

pout może całkiem wydrukować wszystko, co na niego rzucisz, na przykład (pożyczanie dataz innej odpowiedzi):

data = {'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}
pout.vs(data)

spowoduje wydrukowanie na ekranie wyników takich jak:

{
    'a': 2,
    'b':
    {
        'y':
        {
            't2': 5,
            't1': 4
        },
        'x': 3
    }
}

lub możesz zwrócić sformatowany ciąg wyjściowy swojego obiektu:

v = pout.s(data)

Jego podstawowym przypadkiem użycia jest debugowanie, więc nie dusi się na instancjach obiektów ani niczego, i obsługuje wyjście Unicode tak, jak można się spodziewać, działa w Pythonie 2.7 i 3.

ujawnienie : Jestem autorem i opiekunem pout.


3

Wziąłem odpowiedź sth i nieznacznie ją zmodyfikowałem, aby pasowała do moich potrzeb zagnieżdżonych słowników i list:

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

Co daje mi dane wyjściowe takie jak:

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

Cóż, tonę to ładnie;)

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: Nie obsługuje listwartości, które nie są dictinstancjami, tj. pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Nie podobają mi się także duże klawisze.
martineau

Twoje rozwiązanie uważa, że ​​nie może być dykt na liście wewnątrz dykta root. Uważa również, że nie chcemy drukować ładnie listy ani krotki. Wreszcie nie używaj wielkich liter, wynik {{a ': 0,' A ': 1} nie byłby poprawny.
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

Napisałem ten prosty kod, aby wydrukować ogólną strukturę obiektu json w Pythonie.

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

wynik dla następujących danych

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)

jest bardzo kompaktowy i wygląda następująco:

{
  function:
  tuple:
  list:
    [
      ...
    ]
  dict:
    {
      a:
      2:
    }
  unicode:
  ('tuple', 'key'):
}

0

Sam jestem względnym nowicjuszem w Pythonie, ale przez ostatnie kilka tygodni pracowałem z zagnieżdżonymi słownikami i właśnie to wymyśliłem.

Powinieneś spróbować użyć stosu. Przekształć klucze ze słownika głównego w listę:

stack = [ root.keys() ]     # Result: [ [root keys] ]

Przechodząc w odwrotnej kolejności od ostatniej do pierwszej, wyszukaj każdy klucz w słowniku, aby sprawdzić, czy jego wartością jest (także) słownik. Jeśli nie, wydrukuj klucz, a następnie usuń go. Jeśli jednak wartością klucza jest słownik, wydrukuj klucz, a następnie dołącz klucze dla tej wartości na końcu stosu i rozpocznij przetwarzanie tej listy w ten sam sposób, powtarzając rekurencyjnie dla każdej nowej listy kluczy.

Jeśli wartością drugiego klucza na każdej liście byłby słownik, po kilku rundach miałbyś coś takiego:

[['key 1','key 2'],['key 2.1','key 2.2'],['key 2.2.1','key 2.2.2'],[`etc.`]]

Zaletą tego podejścia jest to, że wcięcie jest tylko \twielokrotnością długości stosu:

indent = "\t" * len(stack)

Minusem jest to, że aby sprawdzić każdy klucz, musisz przejść do odpowiedniego słownika podrzędnego, chociaż można to łatwo rozwiązać za pomocą zrozumienia listy i prostej forpętli:

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

Należy pamiętać, że takie podejście wymaga oczyszczenia końcowych pustych list i usunięcia ostatniego klucza z dowolnej listy, po której następuje pusta lista (co oczywiście może stworzyć kolejną pustą listę itd.).

Istnieją inne sposoby wdrożenia tego podejścia, ale mam nadzieję, że daje to podstawowe wyobrażenie o tym, jak to zrobić.

EDYCJA: Jeśli nie chcesz przez to wszystko przechodzić, pprintmoduł drukuje zagnieżdżone słowniki w ładnym formacie.


0

Oto funkcja, którą napisałem na podstawie komentarza. Działa tak samo jak json.dumps z wcięciem, ale używam tabulatorów zamiast spacji dla wcięć. W Python 3.2+ można określić wcięcie bezpośrednio jako „\ t”, ale nie w wersji 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 '}'

Dawny:

>>> 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"
    }
}

Nie mogę sprawić, by działało z zagnieżdżonym dyktsem mojego rozwiązania, ponieważ dało mi to błąd UnicodeEncodeError, a także elementy i klucze są konwertowane na ciągi, a jeśli użyjemy liczb lub krotek zawierających listy i dykt? Ostatecznie twoje rozwiązanie bierze pod uwagę, że naszym przedmiotem, który chcemy ładnie wydrukować, musi być dyktando.
y.petremann

Nie próbowałem napisać ogólnej funkcji drukowania dla słownika python. Najwyżej oceniane komentarze już pokazują, jak ładnie wydrukować dykt. Mój wkład polegał na napisaniu alternatywy dla json.dumps z '\ t' do wcięcia zamiast tabulatorów w python 2.7.
Al Conrad,

Zgadzam się z tobą w sprawie napisania alternatywy dla json.dumps, dla mnie obowiązują te same problemy, co w przypadku json.dumps. Możesz także użyć prostego wyrażenia regularnego, aby zmienić typ wcięcia, co uprości kod.
y.petremann

0

Oto coś, co wydrukuje dowolny zagnieżdżony słownik, jednocześnie śledząc po drodze słowniki „nadrzędne”.

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)

To dobry punkt wyjścia do drukowania w różnych formatach, takich jak ten określony w OP. Wszystko, co naprawdę musisz zrobić, to operacje wokół bloków drukowania . Zauważ, że wygląda na to, czy wartość to „OrdersDict ()”. W zależności od tego, czy używasz czegoś z kolekcji typów danych kontenerów , powinieneś zrobić takie zabezpieczenia, aby blok elif nie widział tego jako dodatkowego słownika ze względu na jego nazwę. Na razie przykładowy słownik

example_dict = {'key1': 'value1',
            'key2': 'value2',
            'key3': {'key3a': 'value3a'},
            'key4': {'key4a': {'key4aa': 'value4aa',
                               'key4ab': 'value4ab',
                               'key4ac': 'value4ac'},
                     'key4b': 'value4b'}

wydrukuje

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

~ modyfikowanie kodu w celu dopasowania do formatu pytania ~

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

Korzystając z tego samego przykładowego kodu, wydrukuje następujące:

['key3']
         value3a
['key4', 'key4a']
                  value4ab
                  value4ac
                  value4aa
['key4']
         value4b

Nie jest to dokładnie to , czego wymaga OP. Różnica polega na tym, że nadrzędny ^ n jest nadal drukowany, zamiast być nieobecny i zastąpiony spacją. Aby dostać się do formatu OP, musisz zrobić coś takiego: iteracyjnie porównać dicList z lastDict . Możesz to zrobić, tworząc nowy słownik i kopiując do niego zawartość dicList, sprawdzając, czy i w skopiowanym słowniku jest taki sam jak i w lastDict, i - jeśli tak - zapisując białe spacje w tej pozycji i, używając funkcji mnożnika łańcucha .


0

Z tego linku :

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

Właśnie wracam do tego pytania po otrzymaniu odpowiedzi na coś i wprowadzeniu małej, ale bardzo przydatnej modyfikacji. Ta funkcja drukuje wszystkie klucze w drzewie JSON, a także wielkość węzłów liści w tym drzewie.

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

To naprawdę miłe, gdy masz duże obiekty JSON i chcesz dowiedzieć się, gdzie jest mięso. Przykład :

>>> print_JSON_tree(JSON_object)
key1
    value1 : int - 5
    value2 : str - 16
    key2
       value1 : str - 34
       value2 : list - 5623456

To by powiedziało, że większość danych, na których Ci zależy, prawdopodobnie znajduje się w środku, JSON_object['key1']['key2']['value2']ponieważ długość tej wartości sformatowanej jako ciąg jest bardzo duża.


0

Użyj tej funkcji:

def pretty_dict(d, n=1):
    for k in d:
        print(" "*n + k)
        try:
            pretty_dict(d[k], n=n+4)
        except TypeError:
            continue

Nazwij to tak:

pretty_dict(mydict)

To nie działa, jeśli wartości są łańcuchami. Drukuje każdy znak ciągu w nowej linii, ale klawisze wydają się działać dobrze.
Anthony

0

Oto, co wymyśliłem, pracując nad klasą, która musiała napisać słownik w pliku .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

Teraz, jeśli mamy taki słownik:

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

I robimy:

print(_pretty_write_dict(some_dict))

Otrzymujemy:

{
    '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': '',
    },
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.