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를 믹스인한 열거형은 format()이 str()과 일치하게 됩니다. 모든 경우에 열거형의 str()과 format()은 같습니다(사용자가 format()을 재정의하지 않는 한).
전역 enum 데코레이터를 추가합니다. 이 데코레이터는 데코레이트된 열거형의 str()과 repr() (그리고 format())이 유효한 전역 참조가 되도록 바꿉니다. 즉, <RegexFlag.IGNORECASE: 2> 대신 re.IGNORECASE가 됩니다.
동기
IntEnum과 IntFlag의 str()이 값이 아니어서 기존 상수를 대체할 때 버그가 생기고 일이 늘어납니다.
열거형 멤버의 str()과 format()이 서로 다르면 혼란스러울 수 있습니다.
StrEnum을 추가하면서 str()이 value여야 한다고 요구하면, 제공되는 다른 Enum의 str과 일관성이 맞지 않습니다.
Flag 멤버의 이터레이션은 repr()에 직접 영향을 주는데, 좋게 말해도 우아하지 않고 나쁘게 말하면 버그가 있습니다.
근거
표준 라이브러리에서 열거형이 점점 더 흔해지고 있습니다. repr()로 열거형 멤버를 알아볼 수 있고 그 repr()을 쉽게 파싱할 수 있으면 유용하며, 코드를 이해하고 디버깅하는 데 드는 시간과 노력을 줄일 수 있습니다.
그러나 데이터 타입이 믹스인된 열거형(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()만 갱신하면 된다는 점에 유의하십시오.
열거형 멤버의 str(), repr(), format()은 가능한 한 표준 라이브러리 전반에 걸쳐 표준화되어야 합니다. 그러나 Python 3.10까지는 표준 라이브러리의 여러 열거형이 사용자 정의 str() 및/또는 repr()을 갖고 있습니다.
현재 플래그(Flag)의 repr()에는 별칭이 포함되어 있는데, 이는 포함되어서는 안 됩니다. 물론 이를 수정하면 특정 경우에 그 repr()이 이미 바뀌게 됩니다.
명세
열거형 사용 방식은 크게 세 가지 범주로 나뉩니다.
- 단순:
Enum또는Flag데이터 타입 믹스인 없이 새 열거형 클래스를 생성합니다. - 그대로 대체:
IntEnum,IntFlag,StrEnumint또는str의 서브클래스이기도 하며int.__str__또는str.__str__을 사용하는 새 열거형 클래스를 생성합니다. - 사용자 믹스인 열거형과 플래그 사용자가 enum.IntEnum 등을 사용하는 대신 정수, 부동소수점, 문자열 등 원하는 타입의 열거형을 직접 만듭니다.
스타일도 두 가지가 있습니다.
- 일반: 열거형 멤버가 클래스 안에 남아 있고
classname.membername으로 접근하며, (적절한 경우)repr()과str()에 클래스 이름이 나타납니다. - 전역: 열거형 멤버가 해당 모듈의 전역 네임스페이스로 복사되며, (적절한 경우)
repr()과str()에 모듈 이름이 나타납니다.
몇 가지 예시 열거형:
# 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.