Как довольно печатать вложенные словари?
как я могу довольно распечатать словарь с глубиной ~4 в Python? Я пробовал довольно печати с pprint(), но это не сработало:
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(mydict)
Я просто хочу, чтобы отступ ("t") для каждого вложения, так что я получаю что-то вроде этого:
key1
value1
value2
key2
value1
value2
etc.
как я могу это сделать?
15 ответов:
Я не уверен, как именно вы хотите, чтобы форматирование выглядело, но вы можете начать с такой функции:
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))(для пользователя python 2: импортируйте функцию печати из _ _ future__)
моя первая мысль заключалась в том, что сериализатор JSON, вероятно, довольно хорош во вложенных словарях, поэтому я бы обманул и использовал это:
>>> import json >>> print json.dumps({'a':2, 'b':{'x':3, 'y':{'t1': 4, 't2':5}}}, ... sort_keys=True, indent=4) { "a": 2, "b": { "x": 3, "y": { "t1": 4, "t2": 5 } } }
Что касается того, что было сделано, я не вижу ни одного симпатичного принтера, который хотя бы имитирует вывод интерпретатора python с очень простым форматированием, поэтому вот мой :
class Formatter(object): def __init__(self): self.types = {} self.htchar = '\t' self.lfchar = '\n' self.indent = 0 self.set_formater(object, self.__class__.format_object) self.set_formater(dict, self.__class__.format_dict) self.set_formater(list, self.__class__.format_list) self.set_formater(tuple, self.__class__.format_tuple) def set_formater(self, obj, callback): self.types[obj] = callback def __call__(self, value, **args): for key in args: setattr(self, key, args[key]) formater = self.types[type(value) if type(value) in self.types else object] return formater(self, value, self.indent) def format_object(self, value, indent): return repr(value) def format_dict(self, value, indent): items = [ self.lfchar + self.htchar * (indent + 1) + repr(key) + ': ' + (self.types[type(value[key]) if type(value[key]) in self.types else object])(self, value[key], indent + 1) for key in value ] return '{%s}' % (','.join(items) + self.lfchar + self.htchar * indent) def format_list(self, value, indent): items = [ self.lfchar + self.htchar * (indent + 1) + (self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1) for item in value ] return '[%s]' % (','.join(items) + self.lfchar + self.htchar * indent) def format_tuple(self, value, indent): items = [ self.lfchar + self.htchar * (indent + 1) + (self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1) for item in value ] return '(%s)' % (','.join(items) + self.lfchar + self.htchar * indent)инициализировать его :
pretty = Formatter()Он может поддерживать добавление форматеров для определенных типов, вам просто нужно сделать функцию для этого, как этот, и привязать ее к типу, который вы хотите с set_formater:
from collections import OrderedDict def format_ordereddict(self, value, indent): items = [ self.lfchar + self.htchar * (indent + 1) + "(" + repr(key) + ', ' + (self.types[ type(value[key]) if type(value[key]) in self.types else object ])(self, value[key], indent + 1) + ")" for key in value ] return 'OrderedDict([%s])' % (','.join(items) + self.lfchar + self.htchar * indent) pretty.set_formater(OrderedDict, format_ordereddict)по историческим причинам, я держу предыдущий довольно принтер, который был функцией вместо класса, но они оба могут использоваться одинаково, версия класса просто позволяет гораздо больше :
def pretty(value, htchar='\t', lfchar='\n', indent=0): nlch = lfchar + htchar * (indent + 1) if type(value) is dict: items = [ nlch + repr(key) + ': ' + pretty(value[key], htchar, lfchar, indent + 1) for key in value ] return '{%s}' % (','.join(items) + lfchar + htchar * indent) elif type(value) is list: items = [ nlch + pretty(item, htchar, lfchar, indent + 1) for item in value ] return '[%s]' % (','.join(items) + lfchar + htchar * indent) elif type(value) is tuple: items = [ nlch + pretty(item, htchar, lfchar, indent + 1) for item in value ] return '(%s)' % (','.join(items) + lfchar + htchar * indent) else: return repr(value)использовать :
>>> a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':pretty,'unicode':u'\xa7',("tuple","key"):"valid"} >>> a {'function': <function pretty at 0x7fdf555809b0>, 'tuple': ('a', 'b', 1, 2), 'list': ['a', 'b', 1, 2], 'dict': {'a': 1, 2: 'b'}, 'unicode': u'\xa7', ('tuple', 'key'): 'valid'} >>> print(pretty(a)) { 'function': <function pretty at 0x7fdf555809b0>, 'tuple': ( 'a', 'b', 1, 2 ), 'list': [ 'a', 'b', 1, 2 ], 'dict': { 'a': 1, 2: 'b' }, 'unicode': u'\xa7', ('tuple', 'key'): 'valid' }по сравнению с другими версиями :
- это решение выглядит непосредственно для типа объекта, так что вы можете довольно печатать почти все, а не только список или дикт.
- не имеет никакой зависимости.
- все внутри строки, так что вы можете делать все, что вы хочу с этим разобраться.
- класс и функция были протестированы и работают с Python 2.7 и 3.4.
- вы можете иметь все типы объектов внутри, это их представления, а не их содержимое, которое помещается в результат (поэтому строка имеет кавычки, строка Unicode полностью представлена ...).
- С помощью версии класса вы можете добавить форматирование для каждого типа объекта, который вы хотите, или изменить их для уже определенных.
- ключ может быть любого действительного тип.
- отступ и символ новой строки могут быть изменены для всего, что мы хотели бы.
- дикт, список и кортежи довольно напечатаны.
вы могли бы попробовать в YAML через PyYAML. Свой выход можно точн-настроить. Я бы предложил начать со следующего:
print yaml.dump(data, allow_unicode=True, default_flow_style=False)результат очень читаемый; он также может быть проанализирован обратно на Python, если это необходимо.
Edit:
пример:
>>> 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
взял л. х и немного изменил его, чтобы соответствовать моим потребностям вложенных словарей и списков:
def pretty(d, indent=0): if isinstance(d, dict): for key, value in d.iteritems(): print '\t' * indent + str(key) if isinstance(value, dict) or isinstance(value, list): pretty(value, indent+1) else: print '\t' * (indent+1) + str(value) elif isinstance(d, list): for item in d: if isinstance(item, dict) or isinstance(item, list): pretty(item, indent+1) else: print '\t' * (indent+1) + str(item) else: pass, который затем дает мне выходной, как:
>>> xs:schema @xmlns:xs http://www.w3.org/2001/XMLSchema xs:redefine @schemaLocation base.xsd xs:complexType @name Extension xs:complexContent xs:restriction @base Extension xs:sequence xs:element @name Policy @minOccurs 1 xs:complexType xs:sequence xs:element ...
Как и другие опубликованные, вы можете использовать recursion/dfs для печати вложенных данных словаря и рекурсивно вызывать, если это словарь; в противном случае распечатайте данные.
>>> def print_json(data): ... if type(data) == dict: ... for k,v in data.items(): ... print k ... print_json(v) ... else: ... print data ...
СТХ, я тону это довольно;)
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)))
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)
Я написал этот простой код для печати общей структуры объекта json в Python.
def getstructure(data, tab = 0): if type(data) is dict: print ' '*tab + '{' for key in data: print ' '*tab + ' ' + key + ':' getstructure(data[key], tab+4) print ' '*tab + '}' elif type(data) is list and len(data) > 0: print ' '*tab + '[' getstructure(data[0], tab+4) print ' '*tab + ' ...' print ' '*tab + ']'результат для следующих данных
a = {'list':['a','b',1,2],'dict':{'a':1,2:'b'},'tuple':('a','b',1,2),'function':'p','unicode':u'\xa7',("tuple","key"):"valid"} getstructure(a)очень компактный и выглядит так:
{ function: tuple: list: [ ... ] dict: { a: 2: } unicode: ('tuple', 'key'): }
С
yapf:from pprint import pformat from yapf.yapflib.yapf_api import FormatCode dict_example = {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5], '4': {'1': '1', '2': '2', '3': [1, 2, 3, 4, 5]}} dict_string = pformat(dict_example) formatted_code, _ = FormatCode(dict_string) print(formatted_code)выход:
{ '1': '1', '2': '2', '3': [1, 2, 3, 4, 5], '4': { '1': '1', '2': '2', '3': [1, 2, 3, 4, 5] } }
вот что будет печатать любой вложенный словарь, отслеживая при этом" родительские " словари по пути.
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)Это хорошая отправная точка для печати в соответствии с различными форматами, как указано в ОП. Все, что вам действительно нужно сделать, это операции вокруг Print блоки. Обратите внимание, что это выглядит, чтобы увидеть, если значение 'OrderedDict()'. В зависимости от того, используете ли вы что-то из контейнер коллекции типов данных, вы должны сделать такие сейфы, чтобы Элиф блок не видит его в качестве дополнительного словаря из-за его названия. На данный момент, пример словаря, как
example_dict = {'key1': 'value1', 'key2': 'value2', 'key3': {'key3a': 'value3a'}, 'key4': {'key4a': {'key4aa': 'value4aa', 'key4ab': 'value4ab', 'key4ac': 'value4ac'}, 'key4b': 'value4b'}печати
key3a: value3a key3a was found in the following path: ['key3'] key2: value2 key2 was found in the following path: [] key1: value1 key1 was found in the following path: [] key4ab: value4ab key4ab was found in the following path: ['key4', 'key4a'] key4ac: value4ac key4ac was found in the following path: ['key4', 'key4a'] key4aa: value4aa key4aa was found in the following path: ['key4', 'key4a'] key4b: value4b key4b was found in the following path: ['key4']~изменение кода в соответствии с форматом вопроса~
lastDict = list() dicList = list() def prettierPrint(dic, dicList): global lastDict count = 0 for key, value in dic.iteritems(): count+=1 if str(value) == 'OrderedDict()': value = None if not isinstance(value, dict): if lastDict == dicList: sameParents = True else: sameParents = False if dicList and sameParents is not True: spacing = ' ' * len(str(dicList)) print dicList print spacing, print str(value) if dicList and sameParents is True: print spacing, print str(value) lastDict = list(dicList) elif isinstance(value, dict): dicList.append(key) prettierPrint(value, dicList) if dicList: if count == len(dic): dicList.pop() count = 0используя тот же пример кода, он будет печатать следующее:
['key3'] value3a ['key4', 'key4a'] value4ab value4ac value4aa ['key4'] value4bЭто не ровно что требуется в OP. The разница в том, что родитель^n все еще печатается, а не отсутствует и заменяется пробелом. Чтобы перейти к формату OP, вам нужно будет сделать что-то вроде следующего: итеративно сравнить dicList С lastDict. Вы можете сделать это, создав новый словарь и скопировав в него содержимое dicList, проверив, если я в скопированном словаре то же самое, что и я в lastDict, и-если это так-написание пробелов для этого я позиция с помощью функции строкового множителя.
С этой ссылке:
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 ' ', 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(' ',' ') 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>{ 'C' :2, 'B' :1, 'E' :4, (3, 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] } '''
Я просто возвращаюсь к этому вопросу после принятия Нответ и делает небольшую, но очень полезную модификацию. Эта функция печатает все ключи в дереве JSON а также размер листовых узлов в это дерево.
def print_JSON_tree(d, indent=0): for key, value in d.iteritems(): print ' ' * indent + unicode(key), if isinstance(value, dict): print; print_JSON_tree(value, indent+1) else: print ":", str(type(d[key])).split("'")[1], "-", str(len(unicode(d[key])))это действительно приятно, когда у вас есть большие объекты JSON и вы хотите выяснить, где находится мясо. пример:
>>> print_JSON_tree(JSON_object) key1 value1 : int - 5 value2 : str - 16 key2 value1 : str - 34 value2 : list - 5623456это скажет вам, что большинство данных, о которых вы заботитесь, это наверное, внутри
JSON_object['key1']['key2']['value2']потому что длина этого значения, отформатированного как строка, очень велика.
Я сам относительный новичок python, но я работал с вложенными словарями в течение последних нескольких недель, и это то, что я придумал.
вы должны попробовать использовать стек. Сделайте ключи из корневого словаря в список списка:
stack = [ root.keys() ] # Result: [ [root keys] ]переходя в обратном порядке от последнего к первому, найдите каждый ключ в словаре, чтобы увидеть, является ли его значение (также) словарем. Если нет, распечатайте ключ и удалите его. Однако если значение ключа и словарь, распечатайте ключ, затем добавьте ключи для этого значения в конец стека и начните обрабатывать этот список таким же образом, повторяя рекурсивно для каждого нового списка ключей.
если бы значение для второго ключа в каждом списке было словарем, у вас было бы что-то вроде этого после нескольких раундов:
[['key 1','key 2'],['key 2.1','key 2.2'],['key 2.2.1','key 2.2.2'],[`etc.`]]преимущество этого подхода заключается в том, что отступ просто
\tумножить длину стека:indent = "\t" * len(stack)в недостатком является то, что для проверки каждого ключа вам нужно хэшировать до соответствующего под-словаря, хотя это может быть легко обработано с пониманием списка и простым
forпетли:path = [li[-1] for li in stack] # The last key of every list of keys in the stack sub = root for p in path: sub = sub[p] if type(sub) == dict: stack.append(sub.keys()) # And so onимейте в виду, что этот подход потребует от вас очистки конечных пустых списков,и удалить Последний ключ в списке следуют пустой список (который, конечно, может создать еще один пустой список, и так далее).
есть и другие способы реализовать это подход, но, надеюсь, это дает вам базовое представление о том, как это сделать.
EDIT: если вы не хотите проходить через все это, то
pprintмодуль печатает вложенные словари в хорошем формате.
вот функция, которую я написал на основе того, что комментарий sth. Это работает так же, как и json.дампы с отступом, но я использую вкладки вместо пространства для отступов. В Python 3.2+ вы можете указать отступ, чтобы быть '\t' напрямую, но не в 2.7.
def pretty_dict(d): def pretty(d, indent): for i, (key, value) in enumerate(d.iteritems()): if isinstance(value, dict): print '{0}"{1}": {{'.format( '\t' * indent, str(key)) pretty(value, indent+1) if i == len(d)-1: print '{0}}}'.format( '\t' * indent) else: print '{0}}},'.format( '\t' * indent) else: if i == len(d)-1: print '{0}"{1}": "{2}"'.format( '\t' * indent, str(key), value) else: print '{0}"{1}": "{2}",'.format( '\t' * indent, str(key), value) print '{' pretty(d,indent=1) print '}'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" } }
Comments