Есть ли способ правильно распечатать заказанные словари? - PullRequest
86 голосов
/ 29 ноября 2010

Мне нравится модуль pprint в Python. Я часто использую его для тестирования и отладки. Я часто использую параметр ширины, чтобы убедиться, что выходные данные хорошо вписываются в мое окно терминала.

Он работал нормально, пока не добавили новый упорядоченный тип словаря в Python 2.7 (еще одна интересная функция, которая мне действительно нравится). Если я попытаюсь напечатать заказной словарь, он не будет отображаться. Вместо того, чтобы каждая пара ключ-значение находилась в отдельной строке, все это отображается в одной длинной строке, которая многократно переносится и ее трудно прочитать.

У кого-нибудь здесь есть способ заставить его печататься красиво, как старые неупорядоченные словари? Я мог бы что-то выяснить, возможно, используя метод PrettyPrinter.format, если бы я потратил достаточно времени, но мне интересно, если кто-нибудь здесь уже знает о решении.

ОБНОВЛЕНИЕ: Я отправил отчет об ошибке для этого. Вы можете увидеть это на http://bugs.python.org/issue10592.

Ответы [ 13 ]

120 голосов
/ 04 февраля 2011

В качестве временного решения вы можете попробовать создать дамп в формате JSON.Вы теряете некоторую информацию о типах, но она выглядит красиво и сохраняет порядок.

import json

pprint(data, indent=4)
# ^ugly

print(json.dumps(data, indent=4))
# ^nice
14 голосов
/ 29 ноября 2010

Следующее будет работать, если порядок вашего OrderedDict - альфа-сортировка, так как pprint будет сортировать dict перед печатью.

pprint(dict(o.items()))
8 голосов
/ 29 ноября 2010

Вот еще один ответ, который работает путем переопределения и внутреннего использования функции pprint(). В отличие от моего более раннего он будет обрабатывать OrderedDict внутри другого контейнера, такого как list, и также должен иметь возможность обрабатывать любые необязательные аргументы ключевого слова, однако это не делает иметь ту же степень контроля над выходом, что и другой.

Он работает, перенаправляя вывод функции stock во временный буфер, а затем переносит слово перед отправкой в ​​поток вывода. Хотя конечный результат не очень хорош, он приличный и может быть «достаточно хорошим» для использования в качестве обходного пути.

Обновление 2.0

Упрощается с помощью модуля стандартной библиотеки textwrap и модифицируется для работы в оба Python 2 и 3.

from collections import OrderedDict
try:
    from cStringIO import StringIO
except ImportError:  # Python 3
    from io import StringIO
from pprint import pprint as pp_pprint
import sys
import textwrap

def pprint(object, **kwrds):
    try:
        width = kwrds['width']
    except KeyError: # unlimited, use stock function
        pp_pprint(object, **kwrds)
        return
    buffer = StringIO()
    stream = kwrds.get('stream', sys.stdout)
    kwrds.update({'stream': buffer})
    pp_pprint(object, **kwrds)
    words = buffer.getvalue().split()
    buffer.close()

    # word wrap output onto multiple lines <= width characters
    try:
        print >> stream, textwrap.fill(' '.join(words), width=width)
    except TypeError:  # Python 3
        print(textwrap.fill(' '.join(words), width=width), file=stream)

d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
lod = [OrderedDict((('john',1), ('paul',2), ('mary',3))),
       OrderedDict((('moe',1), ('curly',2), ('larry',3))),
       OrderedDict((('weapons',1), ('mass',2), ('destruction',3)))]

Пример вывода:

pprint(d, width=40)

»{'john': 1, 'mary': 3, 'paul': 2}

pprint(od, width=40)

»OrderedDict([('john', 1), ('paul', 2),
('mary', 3)])

pprint(lod, width=40)

»[OrderedDict([('john', 1), ('paul', 2),
('mary', 3)]), OrderedDict([('moe', 1),
('curly', 2), ('larry', 3)]),
OrderedDict([('weapons', 1), ('mass',
2), ('destruction', 3)])]

7 голосов
/ 05 марта 2015

Чтобы распечатать заказанный дикт, например,

from collections import OrderedDict

d=OrderedDict([
    ('a', OrderedDict([
        ('a1',1),
        ('a2','sss')
    ])),
    ('b', OrderedDict([
        ('b1', OrderedDict([
            ('bb1',1),
            ('bb2',4.5)])),
        ('b2',4.5)
    ])),
])

Я делаю

def dict_or_OrdDict_to_formatted_str(OD, mode='dict', s="", indent=' '*4, level=0):
    def is_number(s):
        try:
            float(s)
            return True
        except ValueError:
            return False
    def fstr(s):
        return s if is_number(s) else '"%s"'%s
    if mode != 'dict':
        kv_tpl = '("%s", %s)'
        ST = 'OrderedDict([\n'; END = '])'
    else:
        kv_tpl = '"%s": %s'
        ST = '{\n'; END = '}'
    for i,k in enumerate(OD.keys()):
        if type(OD[k]) in [dict, OrderedDict]:
            level += 1
            s += (level-1)*indent+kv_tpl%(k,ST+dict_or_OrdDict_to_formatted_str(OD[k], mode=mode, indent=indent, level=level)+(level-1)*indent+END)
            level -= 1
        else:
            s += level*indent+kv_tpl%(k,fstr(OD[k]))
        if i!=len(OD)-1:
            s += ","
        s += "\n"
    return s

print dict_or_OrdDict_to_formatted_str(d)

Что дает

"a": {
    "a1": 1,
    "a2": "sss"
},
"b": {
    "b1": {
        "bb1": 1,
        "bb2": 4.5
    },
    "b2": 4.5
}

или

print dict_or_OrdDict_to_formatted_str(d, mode='OD')

который дает

("a", OrderedDict([
    ("a1", 1),
    ("a2", "sss")
])),
("b", OrderedDict([
    ("b1", OrderedDict([
        ("bb1", 1),
        ("bb2", 4.5)
    ])),
    ("b2", 4.5)
]))
5 голосов
/ 24 августа 2015

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

Обратите внимание, что это влияет на функцию items().Поэтому вы можете захотеть сохранить и восстановить переопределенные функции после выполнения pprint.

from collections import OrderedDict
import pprint

class ItemKey(object):
  def __init__(self, name, position):
    self.name = name
    self.position = position
  def __cmp__(self, b):
    assert isinstance(b, ItemKey)
    return cmp(self.position, b.position)
  def __repr__(self):
    return repr(self.name)

OrderedDict.items = lambda self: [
    (ItemKey(name, i), value)
    for i, (name, value) in enumerate(self.iteritems())]
OrderedDict.__repr__ = dict.__repr__

a = OrderedDict()
a[4] = '4'
a[1] = '1'
a[2] = '2'
print pprint.pformat(a) # {4: '4', 1: '1', 2: '2'}
2 голосов
/ 15 февраля 2014

Это довольно грубо, но мне просто нужен был способ визуализации структуры данных, состоящей из любых произвольных отображений и итераций, и это то, что я придумал, прежде чем отказаться.Он рекурсивный, поэтому он будет просто попадать во вложенные структуры и списки.Я использовал абстрактные базовые классы Mapping и Iterable из коллекций для обработки практически чего угодно.

Я стремился к почти yaml-подобному выводу с лаконичным кодом Python, но не совсем это сделал.

def format_structure(d, level=0):
    x = ""
    if isinstance(d, Mapping):
        lenk = max(map(lambda x: len(str(x)), d.keys()))
        for k, v in d.items():
            key_text = "\n" + " "*level + " "*(lenk - len(str(k))) + str(k)
            x += key_text + ": " + format_structure(v, level=level+lenk)
    elif isinstance(d, Iterable) and not isinstance(d, basestring):
        for e in d:
            x += "\n" + " "*level + "- " + format_structure(e, level=level+4)
    else:
        x = str(d)
    return x

и некоторые тестовые данные, использующие OrderedDict и списки OrderedDicts ... (простому Python нужны литералы OrderedDict sooo bad ...)

d = OrderedDict([("main",
                  OrderedDict([("window",
                                OrderedDict([("size", [500, 500]),
                                             ("position", [100, 900])])),
                               ("splash_enabled", True),
                               ("theme", "Dark")])),
                 ("updates",
                  OrderedDict([("automatic", True),
                               ("servers",
                                [OrderedDict([("url", "http://server1.com"),
                                              ("name", "Stable")]),
                                 OrderedDict([("url", "http://server2.com"),
                                              ("name", "Beta")]),
                                 OrderedDict([("url", "http://server3.com"),
                                              ("name", "Dev")])]),
                               ("prompt_restart", True)])),
                 ("logging",
                  OrderedDict([("enabled", True),
                               ("rotate", True)]))])

print format_structure(d)

выдает следующий вывод:

   main: 
               window: 
                         size: 
                             - 500
                             - 500
                     position: 
                             - 100
                             - 900
       splash_enabled: True
                theme: Dark
updates: 
            automatic: True
              servers: 
                     - 
                          url: http://server1.com
                         name: Stable
                     - 
                          url: http://server2.com
                         name: Beta
                     - 
                          url: http://server3.com
                         name: Dev
       prompt_restart: True
logging: 
       enabled: True
        rotate: True

У меня были некоторые мысли по поводу использования str.format () для лучшего выравнивания, но я не хотел копаться в этом.Вам нужно было бы динамически указывать ширину поля в зависимости от желаемого типа выравнивания, что может быть сложно или громоздко.

В любом случае, это показывает мои данные в удобочитаемой иерархической форме, так что это работает для меня!

2 голосов
/ 29 ноября 2010
def pprint_od(od):
    print "{"
    for key in od:
        print "%s:%s,\n" % (key, od[key]) # Fixed syntax
    print "}"

Ну вот, ^^

for item in li:
    pprint_od(item)

или

(pprint_od(item) for item in li)
1 голос
/ 05 апреля 2019

Я протестировал этот безобразный хак на основе python3.5, основанный на патчах для обезьян, и он работает:

pprint.PrettyPrinter._dispatch[pprint._collections.OrderedDict.__repr__] = pprint.PrettyPrinter._pprint_dict


def unsorted_pprint(data):
    def fake_sort(*args, **kwargs):
        return args[0]
    orig_sorted = __builtins__.sorted
    try:
        __builtins__.sorted = fake_sort
        pprint.pprint(data)
    finally:
        __builtins__.sorted = orig_sorted

Вы заставляете pprint использовать обычное основанное на диктовке резюме, а также отключаете сортировку по продолжительности вызова, чтобы никакие ключи не сортировались для печати. ​​

1 голос
/ 09 декабря 2016

Вы также можете использовать это упрощение ответа kzh :

pprint(data.items(), indent=4)

Он сохраняет порядок и будет выводить почти то же, что и ответ webwurst ( печать через JSON Dump ).

1 голос
/ 03 февраля 2012

Метод pprint() просто вызывает метод __repr__() вещей в нем, и OrderedDict, кажется, не имеет большого значения в своем методе (или не имеет такового или чего-то еще).

Вот дешевое решение, которое должно работать ЕСЛИ ВЫ НЕ ЗАБЫВАЕТЕ, ЧТО ОКАЗЫВАЕТСЯ ВИДИМОСТЬ В ВЫХОДЕ ПЕЧАТИ , что может быть большим, если:

class PrintableOrderedDict(OrderedDict):
    def __repr__(self):
        return dict.__repr__(self)

Я на самом деле удивлен, что порядок не сохранился ... ну, хорошо.

...