Любой способ правильно напечатать упорядоченные словари?
Мне нравится модуль pprint в Python. Я использую его для тестирования и отладки. Я часто использую параметр ширины, чтобы убедиться, что выход хорошо вписывается в мое окно терминала.
Он отлично работал, пока не добавил новый упорядоченный тип словаря в Python 2.7 (еще одна интересная функция, которая мне очень нравится). Если я попытаюсь напечатать упорядоченный словарь, он не будет хорошо отображаться. Вместо того, чтобы иметь каждую пару ключевых значений в своей собственной строке, все это проявляется на одной длинной строке, которая многократно обертывается и ее трудно читать.
У кого-нибудь есть способ сделать его печатным, как старые неупорядоченные словари? Вероятно, я мог бы что-то выяснить, возможно, используя метод PrettyPrinter.format, если я потрачу достаточно времени, но мне интересно, знает ли кто-нибудь об этом решение.
ОБНОВЛЕНИЕ: Я написал для этого отчет об ошибке. Вы можете увидеть его на http://bugs.python.org/issue10592.
Ответы
Ответ 1
В качестве временного обходного пути вы можете попробовать демпинг в формате JSON.
Вы теряете информацию о типе, но он выглядит красиво и сохраняет порядок.
import json
pprint(data, indent=4)
# ^ugly
print(json.dumps(data, indent=4))
# ^nice
Ответ 2
Следующее будет работать, если порядок вашего OrderedDict является альфа-сортировкой, так как pprint будет сортировать файл перед печатью.
pprint(dict(o.items()))
Ответ 3
Вот еще один ответ, который работает путем переопределения и использования функции запаса pprint()
внутри. В отличие от моего более раннего он будет обрабатывать OrderedDict
внутри другого контейнера, такого как list
, а также должен обрабатывать любые необязательные аргументы ключевого слова, но это не имеют ту же степень контроля над выходом, что и другой.
Он работает, перенаправляя вывод функции запаса во временный буфер, а затем обертывание слов, прежде чем отправлять его в выходной поток. Хотя конечный результат производства не является исключительно красивым, он приличный и может быть "достаточно хорошим" для использования в качестве обходного пути.
Обновление 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)])]
Ответ 4
Чтобы напечатать упорядоченный dict, например
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
Это способ, который взламывает реализацию 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'}
Ответ 6
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)
Ответ 7
Это довольно грубо, но мне просто нужен способ визуализировать структуру данных, состоящую из любых произвольных Mappings и Iterables, и это то, что я придумал, прежде чем сдаться. Он рекурсивный, поэтому он будет попадать вложенные структуры и списки просто отлично. Я использовал базовые классы 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... (sheesh Python нуждается в литералах OrderedDict sooo badly...)
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() для лучшего выравнивания, но мне не хотелось врываться в него. Вам нужно будет динамически указывать ширину поля в зависимости от типа выравнивания, который вы хотите получить, либо сложным, либо громоздким.
В любом случае, это показывает мне мои данные в читабельном иерархическом порядке, поэтому это работает для меня!
Ответ 8
Я протестировал этот нечестивый хак на основе 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
использовать обычную сводку на основе dict, а также отключаете сортировку на время вызова, чтобы никакие ключи фактически не сортировались для печати.
Ответ 9
Метод pprint()
просто вызывает метод __repr__()
вещей в нем, а OrderedDict
, похоже, мало что делает в этом методе (или не имеет одного или что-то).
Здесь дешевое решение, которое должно работать, ЕСЛИ ВЫ НЕ УКАЗАНЫ О ЗАКАЗЕ, ВИДИМЫМ В ПРЯМОЙ ВЫХОДЕ, которая может быть большой, если:
class PrintableOrderedDict(OrderedDict):
def __repr__(self):
return dict.__repr__(self)
Я действительно удивлен тем, что заказ не сохранился... хорошо.
Ответ 10
Вы также можете использовать это упрощение ответа kzh:
pprint(data.items(), indent=4)
Он сохраняет порядок и выводит почти то же самое, что и webwurst (печатать через json dump).
Ответ 11
Вот мой подход к печати OrderedDict
from collections import OrderedDict
import json
d = OrderedDict()
d['duck'] = 'alive'
d['parrot'] = 'dead'
d['penguin'] = 'exploded'
d['Falcon'] = 'discharged'
print(d)
print(json.dumps(d,indent=4))
OutPut:
OrderedDict([('duck', 'alive'), ('parrot', 'dead'), ('penguin', 'exploded'), ('Falcon', 'discharged')])
{
"duck": "alive",
"parrot": "dead",
"penguin": "exploded",
"Falcon": "discharged"
}
Если вы хотите красиво распечатать словарь с ключами в отсортированном порядке
print(json.dumps(indent=4,sort_keys=True))
{
"Falcon": "discharged",
"duck": "alive",
"parrot": "dead",
"penguin": "exploded"
}
Ответ 12
Вы можете переопределить pprint()
и перехватить вызовы для OrderedDict
. Вот простая иллюстрация. Как написано, код переопределения OrderedDict
игнорирует любые необязательные ключевые слова stream
, indent
, width
или depth
, которые могут быть переданы, но могут быть расширены для их реализации. К сожалению, этот метод не обрабатывает их внутри другого контейнера, например list
OrderDict
from collections import OrderedDict
from pprint import pprint as pp_pprint
def pprint(obj, *args, **kwrds):
if not isinstance(obj, OrderedDict):
# use stock function
return pp_pprint(obj, *args, **kwrds)
else:
# very simple sample custom implementation...
print "{"
for key in obj:
print " %r:%r" % (key, obj[key])
print "}"
l = [10, 2, 4]
d = dict((('john',1), ('paul',2), ('mary',3)))
od = OrderedDict((('john',1), ('paul',2), ('mary',3)))
pprint(l, width=4)
# [10,
# 2,
# 4]
pprint(d)
# {'john': 1, 'mary': 3, 'paul': 2}
pprint(od)
# {
# 'john':1
# 'paul':2
# 'mary':3
# }
Ответ 13
Если элементы словаря имеют один тип, вы можете использовать потрясающую библиотеку обработки данных pandas
:
>>> import pandas as pd
>>> x = {'foo':1, 'bar':2}
>>> pd.Series(x)
bar 2
foo 1
dtype: int64
или
>>> import pandas as pd
>>> x = {'foo':'bar', 'baz':'bam'}
>>> pd.Series(x)
baz bam
foo bar
dtype: object