Форматирование словаря Python - PullRequest
4 голосов
/ 01 мая 2010

Я сделал функцию Python для преобразования словарей в форматированные строки. Моей целью было заставить функцию взять словарь для ввода и превратить его в строку, которая выглядела хорошо. Например, что-то вроде {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}} будет превращено в это:

text:
    Hello
blah:
    hi:
        hello
    hello:
        hi

Это код, который я написал:

indent = 0

def format_dict(d):
    global indent
    res = ""
    for key in d:
        res += ("   " * indent) + key + ":\n"
        if not type(d[key]) == type({}):
            res += ("   " * (indent + 1)) + d[key] + "\n"
        else:
            indent += 1
            res += format_dict(d[key])
            indent -= 1
    return res
#test
print format_dict({'key with text content':'some text', 
                  'key with dict content':
                  {'cheese': 'text', 'item':{'Blah': 'Hello'}}})

Это работает как шарм. Он проверяет, является ли элемент словаря другим словарем, и в этом случае он обрабатывает это или что-то еще, тогда он будет использовать это в качестве значения. Проблема в том, что я не могу иметь словарь и строку вместе в элементе словаря. Например, если я хотел:

blah:
    hi
    hello:
        hello again

не было бы способа сделать это. Есть ли способ, которым я мог бы иметь что-то вроде элемента списка в словаре. Как то так {'blah':{'hi', 'hello':'hello again'}}? И если вы предоставите решение, не могли бы вы сказать мне, как мне нужно изменить мой код (если это потребовало изменений).
Примечание : я использую python 2.5

Ответы [ 6 ]

2 голосов
/ 01 мая 2010

Почему бы просто не использовать yaml ?

import yaml
import StringIO

d = {'key with text content':'some text', 
     'key with dict content':
     {'cheese': 'text', 'item': {'Blah': 'Hello'}}}
s = StringIO.StringIO()
yaml.dump(d, s)
print s.getvalue()

распечатывается:

key with dict content:
  cheese: text
  item: {Blah: Hello}
key with text content: some text

и вы можете загрузить его обратно в DICT

s.seek(0)
d = yaml.load(s)
2 голосов
/ 01 мая 2010

Вы можете просто сохранить список в словаре. Кроме того, лучше не использовать глобальный для хранения отступа. Что-то вроде:

def format_value(v, indent):
    if isinstance(v, list):
         return ''.join([format_value(item, indent) for item in v])
    elif isinstance(v, dict):
         return format_dict(v, indent)
    elif isinstance(v, str):
         return ("   " * indent) + v + "\n"

def format_dict(d, indent=0):
    res = ""
    for key in d:
        res += ("   " * indent) + key + ":\n"
        res += format_value(d[key], indent + 1)
    return res
2 голосов
/ 01 мая 2010

Вы можете выразить словари как списки детей:

{'blah': [
    'hi',
    {'hello':[
        'hello again'
    ]},
    {'goodbye':[
        'hasta la vista, baby'
    ]}
]}

Следствием этого является то, что каждый словарь будет иметь только одну пару ключ-значение. С другой стороны, это означает, что вы можете иметь повторяющиеся ключи и детерминированный порядок, как XML.

РЕДАКТИРОВАТЬ: Если подумать, вы можете просто сложить 'hello' и 'goodbye' в один словарь, хотя лично я нахожу это довольно запутанным, поскольку теперь у вас может быть масса беспорядочных и неупорядоченных вещей , Поэтому я предполагаю, что правило «один ключ на словарь» является скорее рекомендацией, чем требованием.

0 голосов
/ 02 сентября 2013

Почему бы не использовать симпатичную печать, которая уже все это делает?

http://docs.python.org/dev/library/pprint.html

0 голосов
/ 01 мая 2010

Как уже упоминалось, вам нужно использовать списки в качестве значений всякий раз, когда вы хотите, чтобы текст и словарь были на одном уровне. Вот код, который печатает то, что вам нужно.

# -*- coding: utf-8 -*-
#!/usr/bin/env python2.5
# /1841878/formatirovanie-slovarya-python

def pretty_dict(d, indent=0, spacer='.'):
    """
    takes a dict {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}}
    And prints:

    text:
        Hello
    blah:
        hi:
            hello
        hello:
            hi

    """
    kindent = spacer * indent

    if isinstance(d, basestring):
        return kindent + d

    if isinstance(d, list):
        return '\n'.join([(pretty_dict(v, indent, spacer)) for v in d])

    return '\n'.join(['%s%s:\n%s' % (kindent, k, pretty_dict(v, indent + 1, spacer)) 
        for k, v in d.items()])


test_a = {'text':'Hello', 'blah':{'hi':'hello','hello':'hi'}}
test_b = {'key with text content':'some text', 'key with dict content':
    {'cheese': 'text', 'item':{'Blah': 'Hello'}}}
test_c = {'blah':['hi', {'hello':'hello again'}]}
test_d = {'blah': [
    'hi',
    {'hello':[
        'hello again'
    ]},
    {'goodbye':[
        'hasta la vista, baby'
]}
]}


if __name__ == '__main__':
    print pretty_dict(test_a)
    print pretty_dict(test_b)
    print pretty_dict(test_c)
    print pretty_dict(test_d)
0 голосов
/ 01 мая 2010

Словарь - это отображение, поэтому у вас не может быть ключа без значения.Однако самое близкое к этому значение ключа будет иметь значение None.Затем добавьте проверку для None перед строкой if not type(d[key]) == type({}): и continue, чтобы избежать печати значения.Кстати, эта линия будет лучше, как if not isinstance(d[key], dict):.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...