Wie drucke ich verschachtelte Wörterbücher hübsch?

289

Wie kann ich in Python ein Wörterbuch mit einer Tiefe von ~ 4 drucken? Ich habe versucht, hübsch zu drucken pprint(), aber es hat nicht funktioniert:

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

Ich möchte einfach eine Einrückung ( "\t") für jede Verschachtelung, damit ich so etwas bekomme:

key1
    value1
    value2
    key2
       value1
       value2

etc.

Wie kann ich das machen?

Martineau
quelle
29
Was bedeutet "hat nicht funktioniert"? Bitte geben Sie sehr genau an, wie pprint "nicht funktioniert hat".
S.Lott
5
Ich habe jetzt 3 dieser Antworten verwendet (jede in einem bestimmten Szenario gut): @ Kens json-Antwort ist gut, schlägt aber manchmal fehl, wenn das Objekt nicht json-serialisierbar ist (löst eine Ausnahme aus). Wenn @ Kens JSON-Antwort nicht funktioniert, versuchen Sie es mit @ Andys Yaml-Antwort und es sollte funktionieren, aber die String-Ausgabe ist etwas weniger lesbar. Die Antwort von [@ sth] ist die allgemeinste (sollte für jedes Objekt funktionieren und keine Bibliotheken verwenden).
Trevor Boyd Smith

Antworten:

143

Ich bin mir nicht sicher, wie genau die Formatierung aussehen soll, aber Sie könnten mit einer Funktion wie dieser beginnen:

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))
etw
quelle
8
Du weißt, @ Kens konventionelle Antwort ist viel besser als diese. Json behandelt bereits alles und dies kann zu Fehlern führen wie: UnicodeEncodeError: Der Codec 'ascii' kann das Zeichen u '\ xf3' in Position 50 nicht codieren: Ordnungszahl nicht im Bereich (128)
frage mich, warum der
Ich kann nicht dafür sorgen, dass es mit dem verschachtelten Diktat meiner Lösung funktioniert, da es mir einen UnicodeEncodeError gegeben hat. Außerdem wird kein Diktatschlüssel gedruckt, keine Liste und keine Tupel erstellt und keine Python-gültige Syntax beibehalten.
y.petremann
Diese Antwort hat für mich wie ein Zauber gewirkt, aber ich habe eine neue Frage gestapelt. Stackoverflow.com/questions/36972225/…, mit der festgelegt wird, wie viele Werte gedruckt werden sollen.
Gsamaras
Ziemlich gut. Wenn Sie verschachtelte Listen wie in der Frage des OP haben, müssen Sie dafür eine Behandlung hinzufügen. Wenn Sie Probleme mit Py2 haben, kann dies dazu führen, dass Unicode ohne __future__solche Hacks nicht richtig verarbeitet werden kann. In der Antwort wird dies nun erwähnt. Sie müssen diese also überall dort einsetzen, wo sie benötigt werden (oder bereits auf 3 aktualisieren).
Sudo
Das hat für mich gut genug funktioniert: 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

Mein erster Gedanke war, dass der JSON-Serializer wahrscheinlich ziemlich gut in verschachtelten Wörterbüchern ist, also würde ich das betrügen und verwenden:

>>> 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
        }
    }
}
Ken
quelle
40
Das ist cool, druckt aber nicht alle Wörterbücher gut. print json.dumps (myObject .__ dict__, sort_keys = True, indent = 4) #TypeError: <Objekt bei 0x0000000002E6A748> ist nicht JSON-serialisierbar
tponthieux
4
Dies sieht zwar nützlich aus, aber die Ausgabe entspricht nicht den Wünschen des OP.
Martineau
2
@martineau: Die angeforderte Ausgabe des OP macht keinen Sinn, Wörterbücher benötigen Schlüssel pro Wert.
naught101
2
@ naught101: Ein hübscher Drucker kann alles tun, um die gewünschte Ausgabe zu erzielen.
Martineau
22
json.dumps verwendet eine Konvertierungsfunktion als optionales Argument. Mit json.dumps (myObject .__ dict__, sort_keys = True, indent = 4, deault = str) können Sie zumindest eine Objektimplementierung von repr verwenden , um sich selbst zu drucken und zu umgehen der 'nicht JSON serialisierbar' TypeError
RFairey
56

Sie können YAML über PyYAML ausprobieren . Der Ausgang kann fein eingestellt werden. Ich würde vorschlagen, mit folgendem zu beginnen:

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

Das Ergebnis ist sehr gut lesbar; Bei Bedarf kann es auch zurück in Python analysiert werden.

Bearbeiten:

Beispiel:

>>> 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
Andy Mikhaylenko
quelle
1
Die Verwendung von yaml ist sehr interessant, da der Datentyp über dem Format bleibt. Das einzige, was ich dagegen sagen kann, ist, dass es keine gültige Python-Zeichenfolge erzeugt, sondern fast wieder in Python konvertiert werden kann.
y.petremann
1
yaml mag Numpys Version von Skalartypen nicht ... Ich war nicht überrascht, dass dies keine numpy Arrays unterstützt, aber ich hätte die gleiche Ausgabe für a floatund a erwartetnumpy.float64
PhilMacKay
Dieser Ansatz funktionierte auch für mich mit einer Liste von Wörterbüchern
Grant Shannon
36

Nach dem, was getan wurde, sehe ich keinen hübschen Drucker, der zumindest die Ausgabe des Python-Interpreters mit sehr einfacher Formatierung nachahmt. Hier ist meiner:

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)

So initialisieren Sie es:

pretty = Formatter()

Es kann das Hinzufügen von Formatierern für definierte Typen unterstützen. Sie müssen lediglich eine Funktion für diese erstellen und diese mit set_formater an den gewünschten Typ binden:

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)

Aus historischen Gründen behalte ich den vorherigen hübschen Drucker, der eine Funktion anstelle einer Klasse war, aber beide können auf die gleiche Weise verwendet werden. Die Klassenversion erlaubt einfach viel mehr:

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)

Um es zu benutzen :

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

Im Vergleich zu anderen Versionen:

  • Diese Lösung sucht direkt nach dem Objekttyp, sodass Sie fast alles drucken können, nicht nur Listen oder Diktate.
  • Hat keine Abhängigkeit.
  • Alles ist in eine Zeichenfolge eingefügt, sodass Sie damit machen können, was Sie wollen.
  • Die Klasse und die Funktion wurden getestet und funktionieren mit Python 2.7 und 3.4.
  • Sie können alle Arten von Objekten darin haben. Dies sind ihre Darstellungen und nicht ihre Inhalte, die in das Ergebnis eingefügt werden (also Zeichenfolge in Anführungszeichen, Unicode-Zeichenfolge wird vollständig dargestellt ...).
  • Mit der Klassenversion können Sie Formatierungen für jeden gewünschten Objekttyp hinzufügen oder diese für bereits definierte ändern.
  • Schlüssel kann von jedem gültigen Typ sein.
  • Einrückungs- und Zeilenumbruchzeichen können für alles geändert werden, was wir möchten.
  • Dict, List und Tuples sind hübsch gedruckt.
y.petremann
quelle
2
Dies sollte definitiv die akzeptierte Lösung sein - das Fehlen einer Abhängigkeit von JSON ist enorm.
Josh
Es wäre cool, wenn es Objekte machen könnte, indem es sie in Diktate konvertiert und ihren Schlüssel auf den Objekttyp setzt
Alex Cory
Sie können die format_object-Methode grundsätzlich intern oder extern ersetzen, um dies zu tun.
y.petremann
set_formater - brauche zwei t, dies ist ein Tippfehler, sollte Formatierer sein
Nikolay Prokopyev
32

Auf diese Weise können Sie es auf hübsche Weise drucken, zum Beispiel, wenn Ihr Wörterbuchname yasin ist

import json

print (json.dumps(yasin, indent=2))
Yasin Lachini
quelle
5
Dies setzt voraus, dass der Inhalt des Wörterbuchs json-serialisierbar ist, was notwendigerweise nicht wahr ist.
SpiXel
8

Eine weitere Option mit 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)

Ausgabe:

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

Wie andere gepostet haben, können Sie mit rekursion / dfs die verschachtelten Wörterbuchdaten drucken und rekursiv aufrufen, wenn es sich um ein Wörterbuch handelt. Andernfalls drucken Sie die Daten.

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

Eine der pythonischsten Möglichkeiten hierfür ist die Verwendung des bereits erstellten pprint- Moduls.

Das Argument, das Sie zum Definieren der Drucktiefe benötigen, ist wie erwartet depth

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

Das ist es !

Juan-Kabbali
quelle
4

Schmollmund kann alles drucken, was Sie darauf werfen, zum Beispiel (Ausleihen dataaus einer anderen Antwort):

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

würde zu einer Ausgabe führen, die auf dem Bildschirm gedruckt wird wie:

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

oder Sie können die formatierte Zeichenfolgenausgabe Ihres Objekts zurückgeben:

v = pout.s(data)

Der Hauptanwendungsfall ist das Debuggen, damit es nicht an Objektinstanzen oder Ähnlichem erstickt und die Unicode-Ausgabe wie erwartet verarbeitet. Dies funktioniert in Python 2.7 und 3.

Offenlegung : Ich bin der Autor und Betreuer von Schmollmund.

Jaymon
quelle
3

Ich nahm die Antwort von etw und änderte sie leicht, um sie an die Bedürfnisse verschachtelter Wörterbücher und Listen anzupassen:

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

Was mir dann Ausgabe gibt wie:

>>> 
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
                                            ...
Jamie Ivanov
quelle
1

Sth, ich versinke das ist hübsch;)

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)))
VindeX
quelle
1
-1: Behandelt keine listWerte, die keine dictInstanzen sind, dh pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Ich mag es auch nicht, Tasten in Großbuchstaben zu schreiben.
Martineau
Ihre Lösung berücksichtigt, dass es innerhalb einer Liste innerhalb des Root-Diktats kein Diktat geben kann. Es wird auch berücksichtigt, dass wir keine Liste oder ein Tupel hübsch drucken möchten. Schließlich sollten Sie keine Schlüssel groß schreiben, das Ergebnis für {'a': 0, 'A': 1} wäre nicht korrekt.
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)
Bob Lockwood
quelle
1

Ich habe diesen einfachen Code geschrieben, um die allgemeine Struktur eines JSON-Objekts in Python zu drucken.

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

das Ergebnis für die folgenden Daten

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)

ist sehr kompakt und sieht so aus:

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

Ich bin selbst ein relativer Python-Neuling, aber ich habe in den letzten Wochen mit verschachtelten Wörterbüchern gearbeitet, und das hatte ich mir ausgedacht.

Sie sollten versuchen, einen Stapel zu verwenden. Machen Sie die Schlüssel aus dem Stammwörterbuch zu einer Liste einer Liste:

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

Suchen Sie in umgekehrter Reihenfolge vom letzten zum ersten nach jedem Schlüssel im Wörterbuch, um festzustellen, ob sein Wert (auch) ein Wörterbuch ist. Wenn nicht, drucken Sie den Schlüssel und löschen Sie ihn. Wenn der Wert für den Schlüssel jedoch ein Wörterbuch ist, drucken Sie den Schlüssel aus, hängen Sie die Schlüssel für diesen Wert an das Ende des Stapels an und beginnen Sie mit der Verarbeitung dieser Liste auf die gleiche Weise, wobei Sie sie für jede neue Schlüsselliste rekursiv wiederholen.

Wenn der Wert für den zweiten Schlüssel in jeder Liste ein Wörterbuch wäre, hätten Sie nach mehreren Runden so etwas:

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

Der Vorteil dieses Ansatzes besteht darin, dass der Einzug nur die doppelte \tLänge des Stapels beträgt:

indent = "\t" * len(stack)

Der Nachteil ist, dass Sie zum Überprüfen jedes Schlüssels das entsprechende Unterwörterbuch durchsuchen müssen, obwohl dies mit einem Listenverständnis und einer einfachen forSchleife leicht zu handhaben ist :

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

Beachten Sie, dass Sie bei diesem Ansatz nachfolgende leere Listen bereinigen und den letzten Schlüssel in einer Liste löschen müssen, gefolgt von einer leeren Liste (wodurch natürlich eine weitere leere Liste erstellt werden kann usw.).

Es gibt andere Möglichkeiten, diesen Ansatz zu implementieren, aber hoffentlich gibt Ihnen dies eine grundlegende Vorstellung davon, wie es geht.

BEARBEITEN: Wenn Sie das alles nicht durchgehen möchten, pprintdruckt das Modul verschachtelte Wörterbücher in einem schönen Format.

Danwroy
quelle
0

Hier ist eine Funktion, die ich basierend auf dem Kommentar von etw geschrieben habe. Es funktioniert genauso wie json.dumps mit Einzug, aber ich verwende Tabulatoren anstelle von Leerzeichen für Einrückungen. In Python 3.2+ können Sie den Einzug direkt als '\ t' angeben, jedoch nicht in 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 '}'

Ex:

>>> 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"
    }
}
Al Conrad
quelle
Ich kann es nicht mit dem verschachtelten Diktat meiner Lösung zum Laufen bringen, da es mir einen UnicodeEncodeError gab. Außerdem werden Elemente und Schlüssel alle in Zeichenfolgen konvertiert. Was ist, wenn wir Zahlen oder Tupel verwenden, die Listen und Diktate enthalten? Finnaly Ihre Lösung berücksichtigt, dass unser Objekt, das wir schön drucken wollen, ein Diktat sein muss.
y.petremann
Ich habe nicht versucht, eine generische Druckfunktion für ein Python-Diktat zu schreiben. Die am besten bewerteten Kommentare zeigen bereits, wie man ein Diktat hübsch druckt. Mein Beitrag bestand darin, eine Alternative zu json.dumps mit '\ t' zum Einrücken anstelle von Tabulatoren in Python 2.7 zu schreiben.
Al Conrad
Ich stimme Ihnen darin zu, eine Alternative zu json.dumps zu schreiben. Für mich gelten dieselben Probleme wie für json.dumps. Sie können auch einen einfachen regulären Ausdruck verwenden, um den Einzugstyp zu ändern und Ihren Code zu vereinfachen.
y.petremann
0

Hier ist etwas, das jede Art von verschachteltem Wörterbuch druckt und dabei die "übergeordneten" Wörterbücher verfolgt.

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)

Dies ist ein guter Ausgangspunkt für das Drucken in verschiedenen Formaten, wie dem in OP angegebenen. Alles, was Sie wirklich tun müssen, sind Operationen um die Druckblöcke . Beachten Sie, dass der Wert "OrderedDict ()" lautet. Abhängig davon, ob Sie etwas aus Container-Datentypen-Sammlungen verwenden , sollten Sie diese Art von Fail-Safes erstellen, damit der elif- Block es aufgrund seines Namens nicht als zusätzliches Wörterbuch ansieht . Ab sofort ein Beispielwörterbuch wie

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

wird gedruckt

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

~ Code an das Format der Frage anpassen ~

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

Mit demselben Beispielcode wird Folgendes gedruckt:

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

Dies ist nicht genau das , was in OP angefordert wird. Der Unterschied besteht darin, dass ein übergeordnetes Element immer noch gedruckt wird, anstatt abwesend zu sein und durch Leerzeichen ersetzt zu werden. Um zum OP-Format zu gelangen, müssen Sie Folgendes tun: Vergleichen Sie dicList iterativ mit lastDict . Sie können dies tun, indem Sie ein neues Wörterbuch erstellen und den Inhalt von dicList in dieses kopieren, prüfen, ob i im kopierten Wörterbuch mit i in lastDict identisch ist, und - falls dies der Fall ist - mithilfe der Zeichenfolgenmultiplikatorfunktion Leerzeichen an diese i- Position schreiben .

Gavin
quelle
0

Von diesem Link :

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

Ich komme gerade auf diese Frage zurück, nachdem ich die Antwort von etw genommen und eine kleine, aber sehr nützliche Änderung vorgenommen habe. Diese Funktion druckt alle Schlüssel im JSON-Baum sowie die Größe der Blattknoten in diesem Baum.

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

Es ist wirklich schön, wenn Sie große JSON-Objekte haben und herausfinden möchten, wo sich das Fleisch befindet. Beispiel :

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

Dies würde Ihnen sagen, dass sich die meisten Daten, die Sie interessieren, wahrscheinlich im Inneren befinden, JSON_object['key1']['key2']['value2']da die Länge dieses als Zeichenfolge formatierten Werts sehr groß ist.

Ulf Aslak
quelle
0

Verwenden Sie diese Funktion:

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

Nennen Sie es so:

pretty_dict(mydict)
fünfzig Karten
quelle
Dies funktioniert nicht, wenn die Werte Zeichenfolgen sind. Es druckt jedes Zeichen der Zeichenfolge in eine neue Zeile, aber die Tasten scheinen in Ordnung zu funktionieren.
Anthony
0

Folgendes habe ich mir bei der Arbeit an einer Klasse ausgedacht, die ein Wörterbuch in eine TXT-Datei schreiben musste:

@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

Wenn wir nun ein Wörterbuch wie dieses haben:

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

Und wir tun:

print(_pretty_write_dict(some_dict))

Wir bekommen:

{
    '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': '',
    },
}
Edgardo Obregón
quelle