Czy istnieje sposób, aby poprawnie wydrukować uporządkowane słowniki?


Podoba mi się moduł pprint w Pythonie. Często go używam do testowania i debugowania. Często używam opcji szerokości, aby upewnić się, że wyjście dobrze pasuje do mojego okna terminala.
Działało dobrze, dopóki nie dodali nowego

uporządkowany typ słownika
http://www.python.org/dev/peps/pep-0372/
w Pythonie 2.7 (kolejna fajna funkcja, którą bardzo lubię). Jeśli spróbuję ładnie wydrukować uporządkowany słownik, nie wyświetla się on dobrze. Zamiast umieszczać każdą parę klucz-wartość w osobnym wierszu, wszystko to pojawia się w jednym długim wierszu, który zawija się wiele razy i jest trudny do odczytania.
Czy ktoś tutaj ma sposób, aby ładnie drukować jak stare, nieuporządkowane słowniki? Prawdopodobnie mógłbym coś wymyślić, może używając metody PrettyPrinter.format, gdybym spędził wystarczająco dużo czasu, ale zastanawiam się, czy ktoś tutaj już zna rozwiązanie.

UPDATE:

Złożyłem w tej sprawie raport o błędzie. Możesz to zobaczyć pod adresem

http://bugs.python.org/issue10592
http://bugs.python.org/issue10592
.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz spróbować zrzucania JSON jako tymczasowego obejścia.
Tracisz informacje o typie, ale ładnie wygląda i zachowuje porządek.
import jsonpprint(data, indent=4)
# ^uglyprint(json.dumps(data, indent=4))
# ^nice
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Poniższe działania będą działać, jeśli kolejność twojego OrderedDict to Alpha sort, ponieważ pprint posortuje dict przed drukowaniem.
pprint(dict(o.items()))
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto kolejna odpowiedź, która działa poprzez nadpisanie i wewnętrzne użycie funkcji stock
pprint ()
. W przeciwieństwie do mojego

poprzedni,
https://stackoverflow.com/a/4302635/355230
czy on jest

będzie

obsługuje
OrderedDict
w innym kontenerze, takim jak
list
i powinien być w stanie obsłużyć wszelkie dodatkowe argumenty słów kluczowych, jednak nie ma takiego samego stopnia kontroli nad danymi wyjściowymi jak inny.
Działa poprzez przekierowanie wyjścia funkcji stock do tymczasowego bufora, a następnie zawijanie go słowem przed wysłaniem go do strumienia wyjściowego. Chociaż wynik końcowy nie jest wyjątkowo ładny, jest przyzwoity i można go użyć jako obejścia.

Aktualizacja 2.0.0

Uproszczony dzięki standardowej bibliotece modułów
textwrap
i zmodyfikowany do pracy w
zarówno Python 2, jak i 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 textwrapdef 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)))]

Przykład danych wyjściowych:
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)])]
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Aby wydrukować zamówiony dykt, na przykład:
from collections import OrderedDictd=OrderedDict([
('a', OrderedDict([
('a1',1),
('a2','sss')
])),
('b', OrderedDict([
('b1', OrderedDict([
('bb1',1),
('bb2',4.5)])),
('b2',4.5)
])),
])

ja robię
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 sprint dict_or_OrdDict_to_formatted_str(d)

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

lub
print dict_or_OrdDict_to_formatted_str(d, mode='OD')

co daje
("a", OrderedDict([
("a1", 1),
("a2", "sss")
])),
("b", OrderedDict([
("b1", OrderedDict([
("bb1", 1),
("bb2", 4.5)
])),
("b2", 4.5)
]))
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto sposób, w jaki można zhakować implementację
pprint
.
pprint
sortuje klucze przed wydrukowaniem, więc aby zachować porządek, musimy tylko upewnić się, że klucze są posortowane tak, jak chcemy.
Zauważ, że ma to wpływ na funkcję
items ()
.
Więc możesz chcieć zapisać i przywrócić nadpisania funkcji po wpisaniu.
from collections import OrderedDict
import pprintclass 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'}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto moje podejście do ładnego wydrukowania 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"
}

Jeśli chcesz ładnie wydrukować słownik z kluczami w posortowanej kolejności
print json.dumps(indent=4,sort_keys=True)
{
"Falcon": "discharged",
"duck": "alive",
"parrot": "dead",
"penguin": "exploded"
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

def pprint_od(od):
print "{"
for key in od:
print "%s:%s,\n" % (key, od[key]) # Fixed syntax
print "}"

To wszystko ^^
for item in li:
pprint_od(item)

lub
(pprint_od(item) for item in li)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

To dość prymitywne, ale potrzebowałem tylko sposobu na renderowanie struktury danych złożonej z dowolnych mapowań i iteracji, i to właśnie wymyśliłem, zanim się poddałem. Jest rekurencyjny, więc dobrze przechodzi przez zagnieżdżone struktury i listy. Użyłem mapowania i iteracyjnych abstrakcyjnych klas bazowych z kolekcji, aby obsłużyć prawie wszystko.
Miałem na celu uzyskanie prawie yamlowego wyjścia ze zwięzłym kodem w Pythonie, ale nie do końca to zrobiłem.
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

i niektóre dane testowe przy użyciu list OrderedDict i OrderedDicts ... (sheesh Python potrzebuje literałów OrderedDict bardzo źle ...)
d = OrderedDict([("main",
OrderedDict([("window",
OrderedDict([("size", [500, 500]),
("position", [100, 900])])),
("splash_enabled", True),
("theme", "Dark")])),
("updates",
OrderedDict([("automatic", True),
("servers",
[OrderedDict([("url", "[url=http://server1.com"]http://server1.com"[/url];),
("name", "Stable")]),
OrderedDict([("url", "[url=http://server2.com"]http://server2.com"[/url];),
("name", "Beta")]),
OrderedDict([("url", "[url=http://server3.com"]http://server3.com"[/url];),
("name", "Dev")])]),
("prompt_restart", True)])),
("logging",
OrderedDict([("enabled", True),
("rotate", True)]))])print format_structure(d)

generuje następujący wynik:
main: 
window:
size:
- 500
- 500
position:
- 100
- 900
splash_enabled: True
theme: Dark
updates:
automatic: True
servers:
-
url: [url=http://server1.com]http://server1.com[/url]
name: Stable
-
url: [url=http://server2.com]http://server2.com[/url]
name: Beta
-
url: [url=http://server3.com]http://server3.com[/url]
name: Dev
prompt_restart: True
logging:
enabled: True
rotate: True

Zastanawiałem się, jak użyć str.format () w celu lepszego wyrównania, ale nie miałem ochoty się w to zagłębiać. Będziesz musiał dynamicznie ustawiać szerokość marginesu w zależności od rodzaju wyrównania, które chcesz, które będzie złożone lub uciążliwe.
W każdym razie to pokazuje mi moje dane w czytelnej formie hierarchicznej, więc to działa dla mnie!
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Przetestowałem tę złośliwą łatkę małpy opartą na hackach w Pythonie 3.5 i działa:
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

Zmuszasz
pprint
do używania zwykłego przestawienia opartego na dyktowaniu, a także wyłączasz sortowanie na czas trwania połączenia, aby żadne klucze nie były faktycznie sortowane do drukowania.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Od Pythona 3.8:
pprint.PrettyPrinter
udostępnia parametr słowa kluczowego
sort_dicts
.

True

domyślnie, ustawiając ją na

False
, słownik pozostanie nieposortowany.
>>> from pprint import PrettyPrinter>>> x = {'John': 1,
>>> 'Mary': 2,
>>> 'Paul': 3,
>>> 'Lisa': 4,
>>> }>>> PrettyPrinter(sort_dicts=False).pprint(x)

Wyświetli:
{'John': 1, 
'Mary': 2,
'Paul': 3,
'Lisa': 4}

Połączyć:

https://docs.python.org/3/ library/pprint.html
https://docs.python.org/3/library/pprint.html
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Metoda
pprint ()
po prostu wywołuje metodę
__repr __ ()
rzeczy w niej, a
OrderedDict
wydaje się nie robić zbyt wiele w swoim metoda (lub nie go lub coś innego).
Oto tanie rozwiązanie, które powinno działać,

jeśli nie obchodzi Cię kolejność widoczna na wyjściu PPRINT
, która może być duża, jeśli:
class PrintableOrderedDict(OrderedDict):
def __repr__(self):
return dict.__repr__(self)

Jestem naprawdę zaskoczony, że zamówienie nie przetrwało ... cóż, w porządku.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz także skorzystać z tego uproszczenia odpowiedzi

kzh
https://coderoad.ru/4301069/
:
pprint(data.items(), indent=4)

Zachowuje porządek i generuje prawie to samo, co

i
https://coderoad.ru/4301069/
odpowiedź webwursta (

drukuj przez json dump

).
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


W przypadku języka Python & < 3,8 (np. 3,6):
>
Małpa łata
pprint
jest
sortowana
, aby zapobiec sortowaniu.
Będzie to miało tę zaletę, że wszystko działa rekurencyjnie i jest bardziej odpowiednie niż opcja
json
dla tych, którzy muszą na przykład użyć parametru
width
:
<pre class="lang-py prettyprint-override">
import pprint
pprint.sorted = lambda arg, *a, **kw: arg>>> pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)
{'z': 1,
'a': 2,
'c': {'z': 0,
'a': 1}}


Edytuj Usuń
>
Aby posprzątać po tym bałaganie, po prostu uruchom:
pprint.sorted = sort
W rzeczywistości poprawnym rozwiązaniem może być nawet użycie pliku contextmanager:
<pre class="lang-py prettyprint-override">
import pprint
import contextlib@contextlib.contextmanager
def pprint_ordered():
pprint.sorted = lambda arg, *args, **kwargs: arg
yield
pprint.sorted = sorted# usage:with pprint_ordered():
pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)# without it
pprint.pprint({'z': 1, 'a': 2, 'c': {'z': 0, 'a': 1}}, width=20)# prints:
#
# {'z': 1,
# 'a': 2,
# 'c': {'z': 0,
# 'a': 1}}
#
# {'a': 2,
# 'c': {'a': 1,
# 'z': 0},
# 'z': 1}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz nadpisać
pprint ()
i przechwytywać wywołania dla
OrderedDict
. oto prosta ilustracja. Jak napisano, kod nadpisujący
OrderedDict
ignoruje wszelkie opcjonalne słowa kluczowe
stream
,
indent
,
width
or
depth
, które można przekazać, ale można je ulepszyć, aby je zaimplementować. Niestety, ta metoda nie obsługuje ich wewnątrz innego kontenera, takiego jak
list
z
OrderDict
[/code]
from collections import OrderedDict
from pprint import pprint as pp_pprintdef 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
# }
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli wszystkie elementy słownika są tego samego typu, możesz użyć niesamowitej biblioteki do manipulacji danymi
pandas
:
>>> import pandas as pd
>>> x = {'foo':1, 'bar':2}
>>> pd.Series(x)
bar 2
foo 1
dtype: int64

lub
>>> import pandas as pd
>>> x = {'foo':'bar', 'baz':'bam'}
>>> pd.Series(x)
baz bam
foo bar
dtype: object

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się