Bagaimana cara mencetak kamus yang bersarang?

289

Bagaimana saya bisa mencetak kamus dengan kedalaman ~ 4 dengan Python? Saya mencoba mencetak dengan cantik pprint(), tetapi tidak berhasil:

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

Saya hanya ingin lekukan ("\t" ) untuk setiap sarang, sehingga saya mendapatkan sesuatu seperti ini:

key1
    value1
    value2
    key2
       value1
       value2

dll.

Bagaimana saya bisa melakukan ini?

martineau
sumber
29
Apa artinya "tidak berhasil"? Harap tentukan dengan sangat tepat bagaimana sidik jari "tidak berfungsi".
S.Lott
5
Saya sekarang telah menggunakan 3 jawaban ini (masing-masing bagus dalam skenario tertentu): @ json jawaban Ken bagus tetapi kadang-kadang gagal ketika objek tidak dapat json serializable (mengeluarkan pengecualian). jika @ json jawaban Ken tidak bekerja coba @ Andy jawaban yaml dan harus bekerja tetapi output string sedikit kurang dapat dibaca manusia. [@ sth's answer] adalah yang paling umum (harus bekerja untuk objek apa pun dan tidak menggunakan libs).
Trevor Boyd Smith

Jawaban:

143

Saya tidak yakin bagaimana persisnya Anda ingin formatnya terlihat, tetapi Anda bisa mulai dengan fungsi seperti ini:

def pretty(d, indent=0):
   for key, value in d.items():
      print('\t' * indent + str(key))
      if isinstance(value, dict):
         pretty(value, indent+1)
      else:
         print('\t' * (indent+1) + str(value))
sth
sumber
8
Anda tahu jawaban konvensional Ken jauh lebih baik daripada ini. Json sudah menangani semuanya dan ini dapat memberikan kesalahan seperti: UnicodeEncodeError: codec 'ascii' tidak dapat menyandikan karakter u '\ xf3' di posisi 50: ordinal tidak dalam jangkauan (128)
wonderwhy
Saya tidak dapat membuatnya berfungsi dengan diksi bersarang dari solusi saya, karena itu memberi saya UnicodeEncodeError, juga tidak mencetak kunci dict, jangan masuk ke dalam daftar dan tupel dan tidak menyimpan sintaksis python yang valid.
y.petremann
Jawaban ini bekerja seperti pesona bagi saya, namun saya memposting pertanyaan baru stackoverflow.com/questions/36972225/… yang menetapkan batas berapa banyak nilai yang harus dicetak.
gsamaras
Cukup bagus. Jika Anda memiliki daftar bersarang seperti dalam pertanyaan OP, Anda perlu menambahkan beberapa penanganan untuk itu. Jika Anda mengalami masalah di Py2, itu karena ia tidak dapat menangani Unicode dengan benar tanpa peretasan seperti __future__yang dijawab oleh jawabannya sekarang, jadi Anda harus menggunakan yang mana pun dibutuhkan (atau sudah perbarui ke 3).
sudo
Ini bekerja cukup baik untuk saya: 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

Pikiran pertama saya adalah bahwa serializer JSON mungkin cukup bagus di kamus bersarang, jadi saya akan menipu dan menggunakannya:

>>> 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
sumber
40
Ini keren, tetapi tidak mencetak semua kamus dengan baik. print json.dumps (myObject .__ dict__, sort_keys = Benar, indent = 4) #TypeError: <objek di 0x0000000002E6A748> bukan JSON yang dapat disambungkan
tponthieux
4
Meskipun ini terlihat bermanfaat, itu bukan output yang diinginkan OP.
martineau
2
@martineau: Output yang diminta OP tidak masuk akal, kamus membutuhkan kunci per nilai.
naught101
2
@ naught101: Printer cantik dapat melakukan apa pun yang diperlukan untuk menghasilkan output yang diinginkan.
martineau
22
json.dumps mengambil fungsi konversi sebagai argumen opsional, jadi dengan json.dumps (myObject .__ dict__, sort_keys = True, indent = 4, deault = str) Anda setidaknya dapat menggunakan objek implementasi repr untuk mencetak sendiri dan mendapatkan putaran TypeError 'not JSON serializable'
RFairey
56

Anda dapat mencoba YAML melalui PyYAML . Keluarannya dapat disesuaikan. Saya sarankan mulai dengan yang berikut ini:

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

Hasilnya sangat mudah dibaca; itu juga dapat diurai kembali ke Python jika diperlukan.

Edit:

Contoh:

>>> 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
sumber
1
Menggunakan yaml sangat menarik karena menyimpan tipe data di atas formatnya, satu-satunya hal yang dapat saya katakan adalah tidak menghasilkan string python yang valid, tetapi hampir dapat dikonversi kembali menjadi python.
y.petremann
1
yaml tidak suka versi skalar jenis Numpy ... Saya tidak terkejut bahwa ini tidak mendukung array numpy, tapi saya akan mengharapkan output yang sama untuk a floatdannumpy.float64
PhilMacKay
pendekatan ini juga berhasil bagi saya menggunakan daftar kamus
Grant Shannon
36

Seperti yang telah dilakukan, saya tidak melihat ada printer cantik yang setidaknya meniru output interpreter python dengan format yang sangat sederhana jadi inilah milik saya:

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)

Untuk menginisialisasi:

pretty = Formatter()

Itu dapat mendukung penambahan formatters untuk tipe yang didefinisikan, Anda hanya perlu membuat fungsi untuk yang seperti ini dan mengikatnya ke tipe yang Anda inginkan dengan 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)

Untuk alasan historis, saya menyimpan printer cantik sebelumnya yang merupakan fungsi alih-alih kelas, tetapi keduanya dapat digunakan dengan cara yang sama, versi kelas hanya mengizinkan lebih banyak:

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)

Untuk menggunakannya:

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

Dibandingkan dengan versi lain:

  • Solusi ini mencari langsung untuk jenis objek, sehingga Anda dapat mencetak hampir semuanya, tidak hanya daftar atau dikte.
  • Tidak memiliki ketergantungan.
  • Semuanya dimasukkan ke dalam string, sehingga Anda dapat melakukan apa pun yang Anda inginkan dengannya.
  • Kelas dan fungsinya telah diuji dan berfungsi dengan Python 2.7 dan 3.4.
  • Anda dapat memiliki semua jenis objek di dalamnya, ini adalah representasi mereka dan bukan konten mereka yang dimasukkan ke dalam hasil (jadi string memiliki tanda kutip, string Unicode sepenuhnya diwakili ...).
  • Dengan versi kelas, Anda dapat menambahkan pemformatan untuk setiap jenis objek yang Anda inginkan atau mengubahnya untuk yang sudah ditentukan.
  • kunci dapat dari jenis apa pun yang valid.
  • Karakter Indent dan Newline dapat diubah untuk semua yang kita inginkan.
  • Dict, List dan Tuples cukup dicetak.
y.petremann
sumber
2
Ini pasti harus menjadi solusi yang diterima - kurangnya ketergantungan pada JSON sangat besar.
Josh
akan lebih keren jika bisa melakukan objek dengan mengubahnya menjadi dicts dan menetapkan kunci mereka menjadi tipe objek
Alex Cory
Anda pada dasarnya dapat mengganti metode format_object secara internal atau eksternal untuk melakukan itu.
y.petremann
set_formater - butuh dua t, ini salah ketik, harus formatter
Nikolay Prokopyev
32

dengan cara ini Anda dapat mencetaknya dengan cara yang sama misalnya dengan nama kamus Anda yasin

import json

print (json.dumps(yasin, indent=2))
yasin lachini
sumber
5
Ini mengasumsikan bahwa isi kamus adalah json serialize-mampu, yang tentu saja tidak benar.
SpiXel
8

Opsi lain dengan 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)

Keluaran:

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

Seperti yang telah diposting orang lain, Anda dapat menggunakan rekursi / dfs untuk mencetak data kamus bersarang dan menelepon secara rekursif jika itu adalah kamus; jika tidak, cetak data.

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

Salah satu cara paling pythonic untuk itu adalah dengan menggunakan modul print yang sudah dibangun .

Argumen yang Anda butuhkan untuk menentukan kedalaman cetak adalah seperti yang Anda harapkan depth

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

Itu dia !

Juan-Kabbali
sumber
4

cemberut dapat mencetak apa saja yang Anda lemparkan padanya, misalnya (meminjam datadari jawaban lain):

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

akan menghasilkan output yang dicetak ke layar seperti:

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

atau Anda dapat mengembalikan output string yang diformat dari objek Anda:

v = pout.s(data)

Kasus penggunaan utamanya adalah untuk debugging sehingga tidak tersumbat pada instance objek atau apa pun dan menangani output unicode seperti yang Anda harapkan, bekerja di python 2.7 dan 3.

pengungkapan : Saya penulis dan pengelola cibiran.

Jaymon
sumber
3

Saya mengambil jawaban sth dan memodifikasinya sedikit agar sesuai dengan kebutuhan saya akan kamus dan daftar yang bersarang:

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

Yang kemudian memberi saya output seperti:

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

Sth, aku tenggelam itu cantik;)

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
sumber
1
-1: Tidak menangani listnilai yang bukan dictinstance, yaitu pretty({'key': [1, 2, 3]}, indent=4)==> AttributeError: 'int' object has no attribute 'iteritems'. Saya juga tidak suka kunci huruf besar.
martineau
Solusi Anda mempertimbangkan bahwa tidak mungkin ada dikt di dalam daftar di dalam root dikt. Juga mempertimbangkan bahwa kami tidak ingin mencetak awal daftar atau tupel. Akhirnya, jangan menggunakan huruf besar kunci, hasil untuk {'a': 0, 'A': 1} tidak akan benar.
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
sumber
1

Saya menulis kode sederhana ini untuk mencetak struktur umum objek json dengan 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 + ']'

hasil untuk data berikut

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)

sangat kompak dan terlihat seperti ini:

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

Saya seorang pemula python relatif sendiri tetapi saya telah bekerja dengan kamus bersarang selama beberapa minggu terakhir dan ini adalah apa yang saya hasilkan.

Anda harus mencoba menggunakan tumpukan. Buat kunci dari kamus root menjadi daftar daftar:

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

Dengan urutan terbalik dari yang terakhir ke yang pertama, cari setiap kunci dalam kamus untuk melihat apakah nilainya adalah (juga) kamus. Jika tidak, cetak kunci lalu hapus. Namun jika nilai untuk kuncinya adalah kamus, cetak kunci lalu tambahkan kunci untuk nilai itu ke akhir tumpukan, dan mulailah memproses daftar itu dengan cara yang sama, ulangi secara berulang untuk setiap daftar kunci yang baru.

Jika nilai untuk kunci kedua di setiap daftar adalah kamus, Anda akan memiliki sesuatu seperti ini setelah beberapa putaran:

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

Keuntungan dari pendekatan ini adalah bahwa indentasi hanya beberapa \tkali panjang tumpukan:

indent = "\t" * len(stack)

The downside adalah bahwa untuk memeriksa setiap kunci yang Anda perlu hash melalui sub-kamus yang relevan, meskipun ini dapat ditangani dengan mudah dengan pemahaman daftar dan forloop sederhana :

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

Ketahuilah bahwa pendekatan ini akan mengharuskan Anda untuk membersihkan daftar yang kosong, dan untuk menghapus kunci terakhir dalam daftar yang diikuti oleh daftar kosong (yang tentu saja dapat membuat daftar kosong lain, dan sebagainya).

Ada cara lain untuk menerapkan pendekatan ini, tetapi mudah-mudahan ini memberi Anda ide dasar tentang bagaimana melakukannya.

EDIT: Jika Anda tidak ingin melalui semua itu, pprintmodul mencetak kamus bersarang dalam format yang bagus.

danwroy
sumber
0

Inilah fungsi yang saya tulis berdasarkan komentar sth. Ini berfungsi sama dengan json.dumps dengan indent, tapi saya menggunakan tab bukan ruang untuk indentasi. Di Python 3.2+ Anda bisa menentukan indentasi menjadi '\ t' secara langsung, tetapi tidak di 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
sumber
Saya tidak dapat membuatnya berfungsi dengan dikte bersarang solusi saya, karena itu memberi saya UnicodeEncodeError, juga item dan kunci semua dikonversi dalam string, bagaimana jika kita menggunakan angka atau tupel yang berisi daftar dan dikt? Finnaly solusi Anda memperhitungkan bahwa objek kami yang ingin kami cetak harus berupa dict.
y.petremann
Saya tidak mencoba untuk menulis fungsi cetak umum untuk dict python. Komentar berperingkat teratas sudah menunjukkan cara mencetak dict. Kontribusi saya adalah menulis alternatif untuk json.dumps dengan '\ t' untuk indentasi alih-alih tab dengan python 2.7.
Al Conrad
Saya setuju dengan Anda tentang menulis alternatif untuk json.dumps, bagi saya masalah yang sama seperti json.dumps berlaku. Anda juga dapat menggunakan regex sederhana untuk mengubah jenis lekukan, membuat kode Anda lebih sederhana.
y.petremann
0

Berikut adalah sesuatu yang akan mencetak segala jenis kamus bersarang, sambil terus melacak kamus "induk".

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)

Ini adalah titik awal yang baik untuk mencetak sesuai format yang berbeda, seperti yang ditentukan dalam OP. Yang perlu Anda lakukan hanyalah operasi di sekitar blok Cetak . Perhatikan bahwa ini terlihat untuk melihat apakah nilainya adalah 'OrderedDict ()'. Bergantung pada apakah Anda menggunakan sesuatu dari Koleksi tipe data Container , Anda harus membuat semacam brankas ini sehingga blok elif tidak melihatnya sebagai kamus tambahan karena namanya. Sampai sekarang, kamus contoh suka

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

akan dicetak

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

~ mengubah kode agar sesuai dengan format pertanyaan ~

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

Menggunakan kode contoh yang sama, itu akan mencetak yang berikut:

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

Ini bukan persis apa yang diminta dalam OP. Perbedaannya adalah bahwa orangtua masih dicetak, bukannya tidak ada dan diganti dengan ruang putih. Untuk sampai ke format OP, Anda harus melakukan sesuatu seperti berikut ini: bandingkan iteratif dengan dicList dengan lastDict . Anda dapat melakukan ini dengan membuat kamus baru dan menyalin konten dicList untuk itu, memeriksa apakah saya dalam kamus disalin adalah sama seperti saya di lastDict, dan - jika - menulis spasi dengan yang saya posisi menggunakan fungsi string yang multiplier .

gavin
sumber
0

Dari tautan ini :

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]
}
'''
pengguna2757572
sumber
0

Saya hanya kembali ke pertanyaan ini setelah mengambil jawaban sth dan membuat modifikasi kecil tapi sangat berguna. Fungsi ini mencetak semua kunci di pohon JSON serta ukuran simpul daun di pohon itu.

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

Sangat menyenangkan ketika Anda memiliki objek JSON besar dan ingin mengetahui di mana dagingnya. Contoh :

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

Ini akan memberi tahu Anda bahwa sebagian besar data yang Anda pedulikan mungkin ada di dalam JSON_object['key1']['key2']['value2']karena panjang nilai yang diformat sebagai string sangat besar.

Ulf Aslak
sumber
0

Gunakan fungsi ini:

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

Sebut saja seperti ini:

pretty_dict(mydict)
lima puluh kartu
sumber
Ini tidak berfungsi jika nilainya adalah string. Ini mencetak setiap karakter string pada baris baru, tetapi tombol tampaknya berfungsi dengan baik.
Anthony
0

Inilah yang saya buat ketika mengerjakan kelas yang perlu menulis kamus dalam file .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

Sekarang, jika kita memiliki kamus seperti ini:

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

Dan kami melakukannya:

print(_pretty_write_dict(some_dict))

Kita mendapatkan:

{
    '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
sumber