PEP 663 – Enum str(), repr() 및 format() 동작 표준화
- Author:
- Ethan Furman <ethan at stoneleaf.us>
- Discussions-To:
- Python-Dev list
- Status:
- Rejected
- Type:
- Informational
- Created:
- 30-Jun-2021
- Python-Version:
- 3.11
- Post-History:
- 20-Jul-2021, 02-Nov-2021
- Resolution:
- Python-Dev message
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
다양한 Enum 타입의 repr(), str() 및 format()을 의도한 목적에 더 잘 부합하도록 업데이트합니다. 예를 들어 IntEnum의 str()은 format()과 일치하도록 변경되는 반면, 사용자가 int와 혼합하여 만든 enum은 format()이 str()과 일치하도록 변경됩니다. 모든 경우에 enum의 str() 및 format()은 동일합니다(사용자가 format()을 재정의하지 않는 한).
데코레이트된 enum의 str() 및 repr() (그리고 format())을 유효한 전역 참조로 변경하는 전역 enum 데코레이터를 추가합니다. 즉, <RegexFlag.IGNORECASE: 2> 대신 re.IGNORECASE가 됩니다.
동기
IntEnum 및 IntFlag의 str()이 값이 아니면 기존 상수를 교체할 때 버그와 추가 작업이 발생합니다.
enum 멤버의 str()과 format()이 서로 다르면 혼란스러울 수 있습니다.
str()이 value가 되어야 한다는 요구 사항을 가진 StrEnum의 추가는 다른 제공 Enum의 str과 일관되지 않습니다.
repr()에 직접 영향을 미치는 Flag 멤버의 순회는 기껏해야 세련되지 못하고, 최악의 경우 버그가 있습니다.
근거
Enum이 표준 라이브러리에서 점점 더 흔해지고 있으므로, repr()을 통해 enum 멤버를 식별할 수 있고 해당 repr()을 쉽게 파싱할 수 있으면 코드를 이해하고 디버깅하는 데 유용하며 시간과 노력을 절약할 수 있습니다.
그러나 혼합 데이터 타입을 사용하는 enum(IntEnum, IntFlag 및 새로 추가된 StrEnum)은 자신이 대체하는 상수와 하위 호환성이 더 높아야 합니다. 구체적으로 str(replacement_enum_member) == str(original_constant)이 참이어야 하며, format()에 대해서도 동일해야 합니다.
IntEnum, IntFlag 및 StrEnum은 기존 정수 및 문자열 상수를 가능한 한 그대로 대체할 수 있어야 합니다. 이를 위해 각각의 str()출력은 고유 값이어야 합니다. 예를 들어 Color가 IntEnum인 경우:
>>> Color.RED
<Color.RED: 1>
>>> str(Color.RED)
'1'
>>> format(Color.RED)
'1'
format()은 이미 올바른 출력을 생성하며, 업데이트가 필요한 것은 str()뿐이라는 점에 유의하십시오.
가능한 한 enum 멤버의 str(), repr() 및 format()은 표준 라이브러리 전반에서 표준화되어야 합니다. 그러나 Python 3.10까지는 표준 라이브러리의 여러 enum이 사용자 지정 str() 및/또는 repr()을 사용합니다.
현재 Flag의 repr()은 별칭을 포함하지만, 그래서는 안 됩니다. 물론 이를 수정하면 특정 경우에는 해당 repr()도 이미 변경됩니다.
사양
enum 사용에는 크게 세 가지 범주가 있습니다.
- 단순:
Enum또는Flag를 사용하여 데이터 타입 혼합 없이 새 enum 클래스를 생성합니다. - 그대로 대체:
IntEnum,IntFlag,StrEnum을 사용하여int또는str도 서브클래싱하고int.__str__또는str.__str__을 사용하는 새 enum 클래스를 생성합니다. - 사용자 혼합 enum 및 flag: 사용자가 enum.IntEnum 등을 사용하는 대신 직접 정수, 부동 소수점, 문자열 및 기타 타입의 enum을 생성합니다.
또한 두 가지 스타일이 있습니다.
- 일반: 열거 멤버가 해당 클래스에 남아 있으며
classname.membername으로 액세스하고, (해당하는 경우)repr()및str()에 클래스 이름이 표시됩니다. - 전역: 열거 멤버가 해당 모듈의 전역 네임스페이스로 복사되며, (해당하는 경우)
repr()및str()에 모듈 이름이 표시됩니다.
일부 샘플 enum:
# module: tools.py
class Hue(Enum): # or IntEnum
LIGHT = -1
NORMAL = 0
DARK = +1
class Color(Flag): # or IntFlag
RED = 1
GREEN = 2
BLUE = 4
class Grey(int, Enum): # or (int, Flag)
BLACK = 0
WHITE = 1
위 열거를 사용하여 다음 두 표에 이전 출력과 새 출력을 표시합니다(빈 셀은 변경 사항이 없음을 나타냅니다).
| style | category | enum repr() | enum str() | enum format() | |
| normal | simple | 3.10 | |||
| new | |||||
| user mixed | 3.10 | 1 | |||
| new | Grey.WHITE | ||||
| int drop-in | 3.10 | Hue.LIGHT | |||
| new | -1 | ||||
| global | simple | 3.10 | <Hue.LIGHT: -1> | Hue.LIGHT | Hue.LIGHT |
| new | tools.LIGHT | LIGHT | LIGHT | ||
| user mixed | 3.10 | <Grey.WHITE: 1 | Grey.WHITE | Grey.WHITE | |
| new | tools.WHITE | WHITE | WHITE | ||
| int drop-in | 3.10 | <Hue.LIGHT: -1> | Hue.LIGHT | ||
| new | tools.LIGHT | -1 | |||
| style | category | flag repr() | flag str() | flag format() | |
| normal | simple | 3.10 | <Color.RED|GREEN: 3> | Color.RED|GREEN | Color.RED|GREEN |
| new | <Color(3): RED|GREEN> | Color.RED|Color.GREEN | Color.RED|Color.GREEN | ||
| user mixed | 3.10 | <Grey.WHITE: 1> | 1 | ||
| new | <Grey(1): WHITE> | Grey.WHITE | |||
| int drop-in | 3.10 | <Color.RED|GREEN: 3> | Color.RED|GREEN | ||
| new | <Color(3): RED|GREEN> | 3 | |||
| global | simple | 3.10 | <Color.RED|GREEN: 3> | Color.RED|GREEN | Color.RED|GREEN |
| new | tools.RED|tools.GREEN | RED|GREEN | RED|GREEN | ||
| user mixed | 3.10 | <Grey.WHITE: 1> | Grey.WHITE | 1 | |
| new | tools.WHITE | WHITE | WHITE | ||
| int drop-in | 3.10 | <Color.RED|GREEN: 3> | Color.RED|GREEN | ||
| new | tools.RED|tools.GREEN | 3 | |||
다음 두 표에 최종 결과가 표시됩니다.
| style | category | enum repr() | enum str() | enum format() |
| normal | simple | <Hue.LIGHT: -1> | Hue.LIGHT | Hue.LIGHT |
| user mixed | <Grey.WHITE: 1> | Grey.WHITE | Grey.WHITE | |
| int drop-in | <Hue.LIGHT: -1> | -1 | -1 | |
| global | simple | tools.LIGHT | LIGHT | LIGHT |
| user mixed | tools.WHITE | WHITE | WHITE | |
| int drop-in | tools.LIGHT | -1 | -1 |
| style | category | flag repr() | flag str() | flag format() |
| normal | simple | <Color(3): RED|GREEN> | Color.RED|Color.GREEN | Color.RED|Color.GREEN |
| user mixed | <Grey(1): WHITE> | Grey.WHITE | Grey.WHITE | |
| int drop-in | <Color(3): RED|GREEN> | 3 | 3 | |
| global | simple | tools.RED|tools.GREEN | RED|GREEN | RED|GREEN |
| user mixed | tools.WHITE | WHITE | WHITE | |
| int drop-in | tools.RED|tools.GREEN | 3 | 3 |
보시다시피, repr()는 주로 멤버가 전역인지 여부에 따라 영향을 받는 반면, str()는 전역인지 또는 드롭인 대체인지에 따라 영향을 받으며, 드롭인 대체 상태가 더 높은 우선순위를 가집니다. 또한 이전 방식에 결함이 있었기 때문에 플래그의 기본 repr()와 str()도 변경되었습니다.
하위 호환성
문자열화된 객체의 하위 호환성은 주요 Python 버전 간에 보장되지 않으며, 소프트웨어가 테스트, 문서, 데이터 구조 및/또는 코드 생성에서 열거형의 repr(), str()및 format()출력을 사용하는 경우 하위 호환성이 깨집니다.
열거형 멤버의 일반적인 사용 방식은 변경되지 않습니다. re.ASCII는 계속 re.ASCII로 사용할 수 있으며 256과 계속 같다고 비교됩니다.
예를 들어 서로 다른 Python 버전 간의 호환성을 보장하기 위해 이전 출력을 유지해야 하는 경우, 소프트웨어 프로젝트는 적절한 메서드를 오버라이드한 자체 열거형 베이스 클래스를 만들어야 합니다.
드롭인 범주의 str()를 변경하면 실제로 향후 IntEnum등이 기존 상수를 대체하는 경우에 발생할 수 있는 호환성 문제를 방지할 수 있다는 점에 유의하십시오.
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.