Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 813 – 예쁜 출력 프로토콜

Author:
Barry Warsaw <barry at python.org>, Eric V. Smith <eric at trueblade.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Created:
07-Nov-2025
Python-Version:
3.16
Post-History:
21-Feb-2026 04-Mar-2026

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 예쁜 출력을 더 사용자 정의 가능하고 편리하게 만들기 위해 제안된 변경 사항 모음인 “예쁜 출력 프로토콜”을 설명합니다.

동기

“예쁜 출력”은 가독성을 높이기 위해 객체 표현을 형식화하는 기능을 제공합니다. 핵심 기능은 표준 라이브러리 pprint 모듈로 구현됩니다. pprint에는 사용자가 객체를 표준 repr() 내장 함수보다 더 읽기 쉬운 형태로 형식화하고 출력하도록 호출할 수 있는 클래스와 API가 포함되어 있습니다. 중요한 사용 사례로는 디버깅을 목적으로 큰 딕셔너리와 기타 복잡한 객체를 예쁘게 출력하는 것이 있습니다.

이 PEP는 더 많은 사용자 정의와 편의를 제공하기 위해 해당 모듈의 기능을 기반으로 합니다. 또한 Rich 라이브러리의 예쁜 출력 프로토콜에서 영감을 받았습니다.

근거

예쁜 출력은 JSON 콘텐츠에서 읽은 딕셔너리와 같은 복잡한 데이터 구조를 표시하는 데 매우 유용합니다. 그러나 기존 pprint 모듈은 자신이 알고 있는 내장 객체만 형식화할 수 있습니다. 클래스가 인스턴스의 예쁜 출력 참여 방식을 사용자 정의할 수 있도록 하면, 특히 디버깅을 위해 복잡한 데이터의 표시를 시각적으로 개선할 수 있는 선택지가 사용자에게 더 많아집니다.

f-문자열과 str.format()!p 변환 지정자를 추가하면, 사용자 친화적인 표시를 사용한 디버깅이 더욱 편리해집니다. 추가 임포트가 필요하지 않으므로, 적어도 가장 일반적인 사용 사례에서는 사용자가 익숙한 “출력 디버깅” 패턴을 쉽게 그대로 활용할 수 있습니다.

이러한 확장 기능은 서로 독립적으로도, 상호 보완적으로도 작동하여 강력한 새로운 사용 사례를 제공합니다.

사양

이 제안은 여러 부분으로 구성됩니다.

__pprint__() 메서드

클래스는 새로운 더블 언더스코어 메서드인 __pprint__()을 구현할 수 있으며, 이 메서드가 있으면 인스턴스의 예쁘게 출력된 표현 일부를 생성합니다. 이는 이 제안 이전까지 객체의 사용자 정의 표현을 생성하는 데 사용된 유일한 메서드였던 __repr__()을 확장합니다. 객체 repr은 예쁜 출력과 구별되는 기능을 제공하므로, 일부 클래스는 예쁜 표시를 더 세밀하게 제어하고자 할 수 있습니다. 객체에 __pprint__() 메서드가 있으면 이를 따르도록 pprint.PrettyPrinter 클래스가 수정됩니다.

__pprint__()은 선택 사항입니다. 이 메서드가 없으면 표준 예쁜 출력기는 완전한 하위 호환성을 위해 __repr__()으로 대체합니다(엄밀히 말하면 pprint.saferepr()이 사용됩니다). 그러나 클래스에 정의된 경우 __pprint__()은 예쁘게 출력할 객체(즉, self)라는 단일 인자를 받습니다.

이 메서드는 객체의 예쁜 표현을 구성하는 데 사용되는 값의 시퀀스를 반환하거나 생성해야 합니다. 이러한 값은 클래스 이름과 같은 표준 클래스 “장식”으로 감싸집니다. 출력된 표현은 일반적으로 위치 인자, 키워드 인자 및 기본 인자를 포함하는 클래스 생성자처럼 보입니다. 값은 다음 형식 중 하나일 수 있습니다.

  • 위치 인자를 나타내는 단일 값입니다. 값 자체가 사용됩니다.
  • 키워드 인자를 나타내는 (name, value)의 2-튜플입니다. name=value의 표현을 사용합니다. name이 “false-y”인 경우 value는 위치 인자로 취급합니다. 튜플 값을 가진 위치 인자를 출력하는 방법입니다. 예제는 Examples를 참조하십시오. name반드시 정확히 str이어야 합니다.
  • 기본값이 있는 키워드 인자를 나타내는 (name, value, default_value)의 3-튜플입니다. valuedefault_value와 같으면 이 튜플은 건너뛰고, 그렇지 않으면 name=value를 사용합니다. name반드시 정확히 str이어야 합니다.

Note

이 프로토콜은 Rich library’s pretty printing protocol과 호환됩니다.

f-stringsstr.format()에 대한 추가 사항

기존의 !s, !r!a 변환 지정자에 더해 새로운 !p 변환 지정자가 추가됩니다. 표현식 value에 이 지정자를 사용하면 value를 유일한 인자로 전달하여 pprint.pformat()을 호출합니다(필요에 따라 pprint 모듈을 가져옵니다).

f-문자열에서만 !p 변환 지정자는 일반적인 구분 기호 : 뒤에 선택적 “형식 지정 사양” 표현식을 허용합니다. 예를 들면 f'{obj!p:expression}'과 같습니다. 형식상 이 표현식은 단일 인자(형식을 지정할 객체)를 받는 호출 가능 객체로 평가되고, f-문자열 대체 값으로 사용되는 문자열을 반환하는 모든 것이 될 수 있습니다. 또한 f-문자열에서 !p 지정자는 obj= 형식과 완전히 호환됩니다. 예를 들면 f'{obj=!p:expression}'과 같습니다. 형식 지정 사양을 지정하지 않으면 위와 같이 pprint.pformat()을 사용합니다.

이 PEP의 initial implementation에서는 적어도 str.format() 호출에서 형식 사양이 허용되지 않는다는 점에 유의하십시오.

C-API에 대한 추가 사항

!p를 지원하기 위해 Limited C API에 새로운 함수 PyObject_Pretty()를 추가합니다. 이 함수는 두 인자를 받습니다. 하나는 예쁘게 출력할 객체를 위한 PyObject *이고, 다른 하나는 선택적 포매터 호출 가능 객체를 위한 PyObject *입니다(NULL일 수 있습니다). 포매터가 NULL이면 이 함수는 pprint 모듈을 가져오고, 객체를 인자로 하여 pprint.pformat()을 호출한 뒤 결과를 반환합니다. 포매터가 NULL이 아니면 객체를 단일 인자로 받아 문자열을 반환하는 호출 가능 객체여야 합니다. 이는 f'{obj!p:expression}'의 이미 평가된 :expression을 지원하는 데 사용됩니다.

예제

사용자 지정 __pprint__() 메서드를 사용하여 객체의 표현을 사용자 지정할 수 있습니다. 예를 들어 다음 클래스와 같습니다.

class Bass:
    def __init__(self, strings: int, pickups: str, active: bool=False):
        self._strings = strings
        self._pickups = pickups
        self._active = active

    def __pprint__(self):
        yield self._strings
        yield 'pickups', self._pickups
        yield 'active', self._active, False

이제 인스턴스를 몇 개 생성하고 이를 예쁘게 출력해 봅시다.

>>> precision = Bass(4, 'split coil P', active=False)
>>> stingray = Bass(5, 'humbucker', active=True)

>>> pprint.pprint(precision)
Bass(4, pickups='split coil P')
>>> pprint.pprint(stingray)
Bass(5, pickups='humbucker', active=True)

!p 변환 지정자는 f-문자열과 str.format()에서 값을 예쁘게 출력하는 데 사용할 수 있습니다.

 >>> print(f'{precision=!p}')
 precision=Bass(4, pickups='split coil P')

 >>> print('{!p}'.format(precision))
 Bass(4, pickups='split coil P')

더 복잡한 객체의 경우 !p를 사용하면 디버깅 출력을 더 읽기 쉽게 만들 수 있습니다.

 >>> import os
 >>> print(os.pathconf_names)
 {'PC_ASYNC_IO': 17, 'PC_CHOWN_RESTRICTED': 7, 'PC_FILESIZEBITS': 18, 'PC_LINK_MAX': 1, 'PC_MAX_CANON': 2, 'PC_MAX_INPUT': 3, 'PC_NAME_MAX': 4, 'PC_NO_TRUNC': 8, 'PC_PATH_MAX': 5, 'PC_PIPE_BUF': 6, 'PC_PRIO_IO': 19, 'PC_SYNC_IO': 25, 'PC_VDISABLE': 9, 'PC_MIN_HOLE_SIZE': 27, 'PC_ALLOC_SIZE_MIN': 16, 'PC_REC_INCR_XFER_SIZE': 20, 'PC_REC_MAX_XFER_SIZE': 21, 'PC_REC_MIN_XFER_SIZE': 22, 'PC_REC_XFER_ALIGN': 23, 'PC_SYMLINK_MAX': 24}

 >>> print(f'{os.pathconf_names = !p}')
 os.pathconf_names = {'PC_ALLOC_SIZE_MIN': 16,
  'PC_ASYNC_IO': 17,
  'PC_CHOWN_RESTRICTED': 7,
  'PC_FILESIZEBITS': 18,
  'PC_LINK_MAX': 1,
  'PC_MAX_CANON': 2,
  'PC_MAX_INPUT': 3,
  'PC_MIN_HOLE_SIZE': 27,
  'PC_NAME_MAX': 4,
  'PC_NO_TRUNC': 8,
  'PC_PATH_MAX': 5,
  'PC_PIPE_BUF': 6,
  'PC_PRIO_IO': 19,
  'PC_REC_INCR_XFER_SIZE': 20,
  'PC_REC_MAX_XFER_SIZE': 21,
  'PC_REC_MIN_XFER_SIZE': 22,
  'PC_REC_XFER_ALIGN': 23,
  'PC_SYMLINK_MAX': 24,
  'PC_SYNC_IO': 25,
  'PC_VDISABLE': 9}

f-문자열에서만 !p 변환 지정자는 형식 지정 사양 표현식도 허용합니다. 이 표현식은 단일 인자를 받고 문자열을 반환하는 호출 가능 객체로 평가되어야 합니다.

 >>> def slappa(da: Bass) -> str:
 ...     return 'All about that bass'

 >>> print(f'{precision=!p:slappa}')
 precision=All about that bass

다음은 위치 인자가 튜플 값을 가지는 예입니다. 이 경우 name이 “false-y”인 2-튜플 형식을 사용합니다.

>>> class Things:
...     def __pprint__(self):
...         yield (None, (1, 2))
...         yield ('', (3, 4))
...         yield ('arg', (5, 6))
...
>>> from rich.pretty import pprint
>>> pprint(Things())
Things((1, 2), (3, 4), arg=(5, 6))

하위 호환성

새로운 기능을 전혀 사용하지 않으면 이 PEP는 완전한 하위 호환성을 유지합니다.

보안 관련 영향

이 제안에는 알려진 보안 관련 영향이 없습니다.

이 내용을 가르치는 방법

pprint 모듈, f-문자열 및 str.format()에 문서와 예제가 추가됩니다. 초보자는 객체를 더 보기 좋게 표현하고 싶을 때까지 이러한 새로운 기능을 배울 필요가 없습니다.

참조 구현

참조 구현은 현재 CPython 메인 브랜치의 PEP 작성자 브랜치에서 사용할 수 있습니다.

거부된 아이디어

우리는 __pprint__() 반환 값에 대한 대안적인 specification을 고려했으며, namedtuple()s, dataclasses, 또는 덕 타이핑된 인스턴스를 반환 형식으로 사용하는 방식이었습니다. 궁극적으로 이 방안을 거부한 이유는 이 함수에서 값을 반환하기 위해 사람들이 새 클래스를 정의하거나 임포트를 추가하도록 강제하고 싶지 않았기 때문입니다.

보류된 아이디어

향후에는 t-문자열에 !p 변환 지원을 추가할 수 있습니다. str.format()에서 !p 변환에 사용하는 :expression 형식의 추가도 보류되었습니다.

미해결 문제

Rich 호환성

출력 형식과 API는 Rich에서 큰 영감을 받았습니다. Rich가 !p:callable과 호환되는 호출 가능 객체를 상당히 쉽게 구현할 수 있다는 것이 이 아이디어입니다. Rich의 API는 인스턴스를 생성자와 유사한 형태로 표현하도록 설계되었으므로, 인자 주변의 “클래스 장식”을 많이 제어할 수 없습니다. Rich는 rich repr 메서드에서 .angular=True을 설정하여 괄호 대신 꺾쇠괄호(즉, <...>)를 사용할 수도 있습니다. 이 PEP는 해당 기능을 지원하지 않지만, 향후에는 지원할 수 있을 것입니다.

이는 문자열, 딕셔너리, 리스트 등과 같은 내장 타입의 보기 좋은 출력 형식을 제어할 방법도 없다는 의미입니다. pprint는 Rich만큼 기능이 풍부하도록 설계된 것이 아니므로(말장난을 의도했습니다!) 이는 괜찮아 보입니다. 이 PEP는 의도적으로 그러한 화려한 기능을 범위 밖으로 간주합니다.

감사의 말

Pablo Galindo Salgado는 PEP 작성자들이 f-문자열에서 !p:callable을 사용하는 방안을 시제품으로 만들고 그 실현 가능성을 입증하는 데 도움을 주었습니다.

각주

현재 없음.

변경 이력

  • 04-Mar-2026
    • f-문자열에만 해당하며(str.format()에는 해당하지 않음), !p 변환 지정자는 선택적인 “형식 지정”을 받습니다.
    • 이 PEP는 더 이상 print() 내장 함수에 pretty 인자를 제안하지 않습니다. f-문자열에 !p:callable 구문이 추가되었으므로 새로운 인자는 필요하지 않습니다.
    • 튜플을 위치 인자로 보기 좋게 출력하려면 2-튜플 값 형식을 사용하고, 인자 이름으로 “거짓으로 평가되는” 값을 전달한다고 명시합니다.
    • 참으로 평가되는 namestr이어야 합니다.
    • f-문자열과 str.format()!p변환은 pprint모듈을 암시적으로 import한다고 명시합니다.
    • 새로운 Limited C API 함수 PyObject_Pretty()를 설명하고 선택적 인자를 추가합니다.