[python] 정렬 된 사전을 제대로 예쁘게 인쇄하는 방법은 없나요?

저는 파이썬의 pprint 모듈을 좋아합니다. 테스트와 디버깅을 위해 많이 사용합니다. 출력이 터미널 창에 잘 맞는지 확인하기 위해 너비 옵션을 자주 사용합니다.

Python 2.7 (내가 정말 좋아하는 또 다른 멋진 기능)에 새로운 정렬 된 사전 유형 을 추가 할 때까지 제대로 작동했습니다 . 정렬 된 사전을 예쁘게 인쇄하려고하면 제대로 표시되지 않습니다. 각 키-값 쌍을 고유 한 줄에 두는 대신 전체 내용이 한 줄에 표시되어 여러 번 줄 바꿈되어 읽기가 어렵습니다.

여기에있는 사람 중에 순서가 지정되지 않은 오래된 사전처럼 멋지게 인쇄 할 수있는 방법이 있습니까? 충분한 시간을 보내면 PrettyPrinter.format 메서드를 사용하여 뭔가 알아낼 수 있지만 여기에있는 누군가가 이미 해결책을 알고 있는지 궁금합니다.

업데이트 : 나는 이것에 대한 버그 보고서를 제출했습니다. http://bugs.python.org/issue10592 에서 볼 수 있습니다 .



답변

임시 해결 방법으로 JSON 형식으로 덤프를 시도 할 수 있습니다. 일부 유형 정보를 잃어 버렸지 만 멋지게 보이고 순서를 유지합니다.

import json

pprint(data, indent=4)
# ^ugly

print(json.dumps(data, indent=4))
# ^nice


답변

다음은 OrderedDict의 순서가 알파 정렬 인 경우 작동합니다. pprint는 인쇄 전에 사전을 정렬하기 때문입니다.

pprint(dict(o.items()))


답변

pprint()내부적으로 stock 함수를 재정의하고 사용하여 작동하는 또 다른 답변이 있습니다 . 달리 내 일 이전됩니다 핸들 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)])]


답변

정렬 된 사전을 인쇄하려면

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)
]))


답변

.NET Framework 구현을 해킹하는 방법은 다음과 같습니다 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'}


답변

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"
}


답변

이것은 매우 조잡하지만 임의의 Mappings 및 Iterables로 구성된 데이터 구조를 시각화하는 방법이 필요했고 이것이 포기하기 전에 생각해 낸 것입니다. 재귀 적이므로 중첩 된 구조와 목록을 통과합니다. 컬렉션의 Mapping 및 Iterable 추상 기본 클래스를 사용하여 거의 모든 것을 처리했습니다.

나는 간결한 파이썬 코드로 출력과 같은 거의 yaml을 목표로했지만 제대로 만들지 못했습니다.

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 및 OrderedDict 목록을 사용하는 일부 테스트 데이터 … (sheesh Python에는 OrderedDict 리터럴이 너무 많이 필요합니다 …)

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 ()을 사용하는 방법에 대해 약간의 생각이 있었지만 파고 들고 싶지는 않았습니다. 원하는 정렬 유형에 따라 필드 너비를 동적으로 지정해야하므로 까다 롭거나 번거로울 수 있습니다.

어쨌든, 이것은 읽을 수있는 계층 적 방식으로 데이터를 보여 주므로 저에게 효과적입니다!