pprint — 데이터 예쁘게 인쇄

pprint — 데이터 예쁘게 인쇄

소스 코드: Lib/pprint.py

pprint 모듈은 임의의 Python 데이터 구조를 인터프리터에 대한 입력으로 사용할 수 있는 형식으로 "예쁘게 인쇄(pretty-print)"하는 기능을 제공해요. 형식화된 구조에 기본 Python 타입이 아닌 객체가 포함되면 그 표현은 로드 가능하지 않을 수 있어요. 파일, 소켓, 클래스 같은 객체와 Python 리터럴로 표현할 수 없는 다른 많은 객체가 포함되면 그럴 수 있어요.

형식화된 표현은 가능하면 객체를 단일 줄에 유지하고, 허용된 너비(기본 80문자로 width 매개변수로 조정 가능)에 맞지 않으면 여러 줄로 나눠요.

버전 3.9에서 변경: types.SimpleNamespace 예쁘게 인쇄 지원 추가.

버전 3.10에서 변경: dataclasses.dataclass 예쁘게 인쇄 지원 추가.

출처: Python 표준 라이브러리

본문

함수 (Functions)

pprint.pp(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=False, underscore_numbers=False)

object의 형식화된 표현을 새 줄과 함께 인쇄해요. 이 함수는 값 검사를 위해 print() 함수 대신 대화형 인터프리터에서 사용될 수 있어요. 팁: 스코프 내에서 사용하기 위해 print = pprint.pp로 재할당할 수 있어요.

매개변수:

  • object (Any) — 인쇄할 객체.
  • stream (file-like object | None) — 그것의 write() 메서드를 호출해 출력이 쓰일 파일류 객체. None(기본)이면 sys.stdout이 사용돼요.
  • indent (int) — 각 중첩 수준에 추가되는 들여쓰기 양.
  • width (int) — 출력에서 줄당 원하는 최대 문자 수. 구조를 width 제약 안에 형식화할 수 없으면 최선을 다해 형식화돼요.
  • depth (int | None) — 인쇄될 수 있는 중첩 수준 수. 인쇄 중인 데이터 구조가 너무 깊으면 다음 포함 수준이 ...로 대체돼요. None(기본)이면 형식화되는 객체의 깊이에 제약이 없어요.
  • compact (bool) — 긴 시퀀스를 형식화하는 방식을 제어. False(기본)면 시퀀스의 각 항목이 별도의 줄에 형식화되고, 그렇지 않으면 너비 내에 맞는 만큼의 항목이 각 출력 줄에 형식화돼요.
  • sort_dicts (bool) — True면 사전이 키 정렬로 형식화되고, 그렇지 않으면 (기본으로) 삽입 순서로 표시돼요.
  • underscore_numbers (bool) — True면 정수가 천 단위 구분자 _ 문자로 형식화되고, 그렇지 않으면 (기본으로) 밑줄이 표시되지 않아요.
>>> import pprint
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
>>> stuff.insert(0, stuff)
>>> pprint.pp(stuff)
[<Recursion on list with id=...>,
 'spam',
 'eggs',
 'lumberjack',
 'knights',
 'ni']

버전 3.8에 추가.

pprint.pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True, underscore_numbers=False)

기본적으로 sort_dictsTrue로 설정한 pp()의 별칭이에요. 그러면 사전의 키가 자동으로 정렬돼요. False가 기본인 pp()를 대신 사용하고 싶을 수도 있어요.

pprint.pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True, underscore_numbers=False)

object의 형식화된 표현을 문자열로 반환해요. indent, width, depth, compact, sort_dicts, underscore_numbers는 형식화 매개변수로 PrettyPrinter 생성자에 전달되며 그 의미는 위 문서에서 설명한 대로예요.

pprint.isreadable(object)

object의 형식화된 표현이 "읽을 수 있는지", 즉 eval()을 사용해 값을 재구성하는 데 사용될 수 있는지 판단해요. 재귀 객체에 대해서는 항상 False를 반환해요.

>>> pprint.isreadable(stuff)
False

pprint.isrecursive(object)

object가 재귀 표현을 요구하는지 판단해요. 이 함수는 아래 saferepr()에 언급된 것과 같은 제한의 적용을 받고, 재귀 객체를 감지하지 못하면 RecursionError를 발생시킬 수 있어요.

pprint.saferepr(object)

__repr__이 재정의되지 않은 dict, list, tuple의 인스턴스 또는 하위 클래스 같은 몇몇 공통 데이터 구조에서 재귀로부터 보호되는 object의 문자열 표현을 반환해요. object의 표현이 재귀 항목을 노출하면 재귀 참조가 <Recursion on typename with id=number>로 표현돼요. 그 외에는 표현이 형식화되지 않아요.

>>> pprint.saferepr(stuff)
"[<Recursion on list with id=...>, 'spam', 'eggs', 'lumberjack', 'knights', 'ni']"

PrettyPrinter 객체

class pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, compact=False, sort_dicts=True, underscore_numbers=False)

PrettyPrinter 인스턴스를 생성해요. 인자는 pp()와 같은 의미를 가져요. 단, 순서가 다르고 sort_dicts가 기본적으로 True라는 점에 주의하세요.

>>> import pprint
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
>>> stuff.insert(0, stuff[:])
>>> pp = pprint.PrettyPrinter(indent=4)
>>> pp.pprint(stuff)
[   ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
    'spam',
    'eggs',
    'lumberjack',
    'knights',
    'ni']
>>> pp = pprint.PrettyPrinter(width=41, compact=True)
>>> pp.pprint(stuff)
[['spam', 'eggs', 'lumberjack',
  'knights', 'ni'],
 'spam', 'eggs', 'lumberjack', 'knights',
 'ni']
>>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
... ('parrot', ('fresh fruit',))))))))
>>> pp = pprint.PrettyPrinter(depth=6)
>>> pp.pprint(tup)
('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))

*버전 3.4에서 변경: compact 매개변수 추가. / *버전 3.8에서 변경: sort_dicts 매개변수 추가. / *버전 3.10에서 변경: underscore_numbers 매개변수 추가. / 버전 3.11에서 변경: sys.stdoutNone이면 더 이상 쓰려고 시도하지 않음.

PrettyPrinter 인스턴스에는 다음 메서드들이 있어요:

PrettyPrinter.pformat(object)

object의 형식화된 표현을 반환해요. 이것은 PrettyPrinter 생성자에 전달된 옵션을 고려해요.

PrettyPrinter.pprint(object)

구성된 스트림에 object의 형식화된 표현을 새 줄과 함께 인쇄해요.

다음 메서드는 같은 이름의 해당 함수에 대한 구현을 제공해요. 인스턴스에서 이 메서드를 사용하는 것이 새 PrettyPrinter 객체를 만들 필요가 없으므로 약간 더 효율적이에요.

PrettyPrinter.isreadable(object)

객체의 형식화된 표현이 "읽을 수 있는지", 즉 eval()을 사용해 값을 재구성하는 데 사용될 수 있는지 판단해요. 재귀 객체에 대해서는 False를 반환한다는 점에 주의하세요. PrettyPrinterdepth 매개변수가 설정되고 객체가 허용된 것보다 깊으면 False를 반환해요.

PrettyPrinter.isrecursive(object)

객체가 재귀 표현을 요구하는지 판단해요. 이 메서드는 하위 클래스가 객체가 문자열로 변환되는 방식을 수정할 수 있게 하는 훅으로 제공돼요. 기본 구현은 saferepr() 구현의 내부를 사용해요.

PrettyPrinter.format(object, context, maxlevels, level)

세 값을 반환해요: 문자열로서의 object의 형식화된 버전, 결과가 읽을 수 있는지 나타내는 플래그, 재귀가 감지되었는지 나타내는 플래그. 첫 인자는 제시할 객체예요. 두 번째는 현재 제시 맥락의 일부인(제시에 영향을 미치는 object의 직접·간접 컨테이너) 객체의 id()를 키로 담는 사전이에요. context에 이미 표현된 객체를 제시해야 하면 세 번째 반환 값은 True여야 해요. format() 메서드에 대한 재귀 호출은 컨테이너에 대한 추가 항목을 이 사전에 추가해야 해요. 세 번째 인자 maxlevels는 재귀에 대한 요청된 제한을 줘요. 요청된 제한이 없으면 0이에요. 이 인자는 재귀 호출에 수정 없이 전달해야 해요. 네 번째 인자 level은 현재 수준을 줘요. 재귀 호출에는 현재 호출의 수준보다 작은 값을 전달해야 해요.

예제 (Example)

pp() 함수와 그 매개변수의 여러 용도를 보여주기 위해, PyPI에서 프로젝트에 대한 정보를 가져와 보죠:

>>> import json
>>> import pprint
>>> from urllib.request import urlopen
>>> with urlopen('https://pypi.org/pypi/sampleproject/1.2.0/json') as resp:
...     project_info = json.load(resp)['info']

기본 형태에서 pp()는 전체 객체를 보여줘요:

>>> pprint.pp(project_info)
{'author': 'The Python Packaging Authority',
 'author_email': '[email protected]',
 'bugtrack_url': None,
 'classifiers': ['Development Status :: 3 - Alpha',
                 'Intended Audience :: Developers',
                 'License :: OSI Approved :: MIT License',
                 'Programming Language :: Python :: 2',
                 'Programming Language :: Python :: 2.6',
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3',
                 'Programming Language :: Python :: 3.2',
                 'Programming Language :: Python :: 3.3',
                 'Programming Language :: Python :: 3.4',
                 'Topic :: Software Development :: Build Tools'],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the project.\n'
                '\n'
                'The file should use UTF-8 encoding and be written using '
                'ReStructured Text. It\n'
                'will be used to generate the project webpage on PyPI, and '
                'should be written for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would include an overview of '
                'the project, basic\n'
                'usage examples, etc. Generally, including the project '
                'changelog in here is not\n'
                'a good idea, although a simple "What\'s New" section for the '
                'most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {'Download': 'UNKNOWN',
                  'Homepage': 'https://github.com/pypa/sampleproject'},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

결과는 특정 깊이로 제한될 수 있어요(더 깊은 내용에는 말줄임표 사용):

>>> pprint.pp(project_info, depth=1)
{'author': 'The Python Packaging Authority',
 'author_email': '[email protected]',
 'bugtrack_url': None,
 'classifiers': [...],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the project.\n'
                '\n'
                'The file should use UTF-8 encoding and be written using '
                'ReStructured Text. It\n'
                'will be used to generate the project webpage on PyPI, and '
                'should be written for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would include an overview of '
                'the project, basic\n'
                'usage examples, etc. Generally, including the project '
                'changelog in here is not\n'
                'a good idea, although a simple "What\'s New" section for the '
                'most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {...},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {...},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

추가로 최대 문자 너비를 제안할 수 있어요. 긴 객체를 쪼갤 수 없으면 지정된 너비를 초과하게 돼요:

>>> pprint.pp(project_info, depth=1, width=60)
{'author': 'The Python Packaging Authority',
 'author_email': '[email protected]',
 'bugtrack_url': None,
 'classifiers': [...],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the '
                'project.\n'
                '\n'
                'The file should use UTF-8 encoding and be '
                'written using ReStructured Text. It\n'
                'will be used to generate the project '
                'webpage on PyPI, and should be written '
                'for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would '
                'include an overview of the project, '
                'basic\n'
                'usage examples, etc. Generally, including '
                'the project changelog in here is not\n'
                'a good idea, although a simple "What\'s '
                'New" section for the most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {...},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {...},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

더 알아보기