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


97

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

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

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

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


2
에 주문 사전에 대한 코멘트를 추가 제안 bugs.python.org/issue7434
네드 Deily에게

답변:


133

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

import json

pprint(data, indent=4)
# ^ugly

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

7
@scottmrogowski 왜 간단하지 pprint.pprint(dict(data))않습니까?
Alfe 2015 년

2
pprint.pprint(dict(data))키의 순서에 신경 쓰지 않으면 잘 작동합니다. 개인적으로 __repr__for OrderedDict가 이와 같은 출력을 생성하지만 키의 순서를 유지하기를 바랍니다.
ws_e_c421 2015 년

9
DICT 중첩 OrderedDicts이있는 경우 @Alfe 그들은 잘 표시되지 않습니다
Catskul

1
또한 키로 정수에 실패
DimmuR

2
@Alfe : 출력이 정렬되지 않았기 때문입니다. 처음에 dict 대신 OrderedDict를 사용하는 이유는 순서가 중요하기 때문입니다.
Teekin

15

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

pprint(dict(o.items()))

2
OrderedDicts는 삽입 순서에 따라 정렬되므로 이는 사용의 일부에 적용될 수 있습니다. 그럼에도 불구하고 OD를로 변환하면 dict모든 것이 한 줄에 배치되는 문제를 피해야합니다.
martineau

8

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


나는 그것을 시도하고 작동합니다. 말했듯이 가장 예쁘지는 않지만 지금까지 본 것 중 최고의 솔루션입니다.
Elias Zamaria

7

정렬 된 사전을 인쇄하려면

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

.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'}

2
좋지만 하위 유형을 지정하고 함수를 재정의하는 것이 좋습니다.
xmedeko

3

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

@AlxVallejo 당신은 python3. 확인하십시오
CHINTAN VADGAMA

2

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

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


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

OrderedDicts 및 다른 유형을 예쁘게 인쇄 할 수있는 하나의 함수를 갖는 방법을 찾고 있습니다. 나는 당신의 함수를 사용하여 OrderedDicts 목록을 예쁘게 인쇄하는 방법을 알지 못합니다.
Elias Zamaria

-1 pprint_od()기능을하지 작업 않는 - for key, item in odA의 문 결과 ValueError: too many values to unpack 들여 쓰기 유일한 출력은 최종 " }" key, item 에서 print괄호에있을 문 필요합니다. 거기 당신은 ^^ 이동
마티

2

나는이 부정한 원숭이 패치 기반 해킹을 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 요약 설명도 비활성화 정렬을 사용합니다.


또한 pretty_print.py로컬 모듈로 복사 하고 해킹 할 수도 있습니다 ( sorted전화 또는 원하는 것을 제거 ).
Karl Rosaen 19.04.05

2

Python 3.8부터 : 키워드 매개 변수를 pprint.PrettyPrinter노출합니다 sort_dicts.

기본적으로 True 이며 False로 설정 하면 사전이 정렬되지 않은 상태로 유지됩니다.

>>> from pprint import PrettyPrinter

>>> x = {'John': 1,
>>>      'Mary': 2,
>>>      'Paul': 3,
>>>      'Lisa': 4,
>>>      }

>>> PrettyPrinter(sort_dicts=False).pprint(x)

출력됩니다 :

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

참조 : https://docs.python.org/3/library/pprint.html


1

pprint()메서드는 그 __repr__()안에있는 사물 의 메서드를 호출하는 것 뿐이며 메서드에서 OrderedDict많은 작업을 수행하지 않는 것 같습니다 (또는 하나 또는 무언가가 없음).

다음은 PPRINT OUTPUT 에서 표시되는 주문에 대해 신경 쓰지 않는 경우 효과가있는 저렴한 솔루션입니다 .

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

주문이 보존되지 않아서 놀랐습니다 ... 아.


파이썬 사전은 해시 맵을 사용하여 구현됩니다. 따라서 OrderedDict (기본 사전과 순서를 유지하기위한 목록의 조합)를 사전으로 변환하면 주문 정보가 손실됩니다. 또한 repr 메서드는 파이썬 코드에서 객체를 나타내는 문자열을 반환해야합니다. 즉, obj == eval (repr (obj)) 또는 최소 repr (obj) == repr (eval (repr (obj)))입니다. OrderedDict의 repr은 이것을 잘 수행합니다. 매우 사람이 읽을 수있는 표현을 제공하는 dict .__ repr__은 완전히 dict 리터럴 ( '{'및 '}'등)의 부작용입니다. OrderedDict에는이 기능이 없습니다.
marr75

1

다음과 같은 kzh 대답의 단순화를 사용할 수도 있습니다 .

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

순서를 유지하고 webwurst 답변 ( json dump를 통해 인쇄) 과 거의 동일하게 출력합니다 .


1

Python <3.8 (예 : 3.6)의 경우 :

원숭이 패치 pprintsorted분류에서 그것을 방지하기 위해. 이것은 재귀 적으로 작동하는 모든 것의 이점을 가질 것이며, json예를 들어 width매개 변수 를 사용해야하는 사람을위한 옵션 보다 더 적합합니다 .

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

편집 : 정리

이 더러운 사업 후에 정리하려면 다음을 실행하십시오. pprint.sorted = sorted

정말 깨끗한 솔루션의 경우 컨텍스트 관리자를 사용할 수도 있습니다.

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}

0

pprint()호출을 재정의 하고 가로 챌 수 OrderedDict있습니다. 여기에 간단한 그림이 있습니다. 기록으로, OrderedDict재정의 코드는 선택적 무시 stream, indent, width, 또는 depth통과되었을 수 있습니다 키워드를하지만,이를 구현하기 위해 강화 될 수있다. 불행하게도이 기술은 같은 같은 다른 컨테이너 내부를 처리하지 않습니다 listOrderDict

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

0

사전 항목이 모두 하나의 유형이면 놀라운 데이터 처리 라이브러리를 사용할 수 있습니다 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

2
그 코드는 무엇을할까요? 여기에있는 다른 솔루션에 비해 어떤 이점이 있습니까?
Elias Zamaria 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.