PEP 604 – 유니언 타입을 X | Y로 작성할 수 있도록 허용
- Author:
- Philippe PRADOS <python at prados.fr>, Maggie Moss <maggiebmoss at gmail.com>
- Sponsor:
- Chris Angelico <rosuav at gmail.com>
- BDFL-Delegate:
- Guido van Rossum <guido at python.org>
- Discussions-To:
- Typing-SIG list
- Status:
- Final
- Type:
- Standards Track
- Topic:
- Typing
- Created:
- 28-Aug-2019
- Python-Version:
- 3.10
- Post-History:
- 28-Aug-2019, 05-Aug-2020
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 타입에 대해 | 연산자를 오버로딩하여 Union[X, Y]를 X | Y로 작성할 수 있게 하고, 이를 isinstance 및 issubclass 호출에서도 사용할 수 있도록 할 것을 제안합니다.
동기
PEP 484와 PEP 526은 변수, 매개변수, 함수 반환값에 타입을 지정하기 위한 제네릭 문법을 제안합니다. PEP 585는 런타임에 제네릭의 매개변수를 노출할 것을 제안합니다. Mypy [1]는 다음과 같은 형태의 문법을 허용합니다.:
annotation: name_type
name_type: NAME (args)?
args: '[' paramslist ']'
paramslist: annotation (',' annotation)* [',']
- 논리합(유니언 타입)을 표현하려면 사용자는
Union[X, Y]를 사용해야 합니다.
이 문법은 장황하여 타입 도입에 도움이 되지 않습니다.
제안
Scala [2]와 Pike [3]에서 영감을 받아, 이 제안은 type.__or__() 연산자를 추가합니다. 이 새로운 연산자를 사용하면 Union[int, str] 대신 int | str로 작성할 수 있습니다. 어노테이션뿐 아니라, 이 표현식의 결과는 isinstance()와 issubclass()에서도 유효하게 됩니다:
isinstance(5, int | str)
issubclass(bool, int | float)
또한 Optional[t] 대신 t | None 또는 None | t로 작성할 수도 있습니다:
isinstance(None, int | None)
isinstance(42, None | int)
명세
새로운 유니언 문법은 함수, 변수, 매개변수 어노테이션에서 허용되어야 합니다.
단순화된 문법
# Instead of
# def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]
def f(list: List[int | str], param: int | None) -> float | str:
pass
f([1, "abc"], None)
# Instead of typing.List[typing.Union[str, int]]
typing.List[str | int]
list[str | int]
# Instead of typing.Dict[str, typing.Union[int, float]]
typing.Dict[str, int | float]
dict[str, int | float]
기존의 typing.Union과 | 문법은 동등해야 합니다.
int | str == typing.Union[int, str]
typing.Union[int, int] == int
int | int == int
Union 내 항목의 순서는 동등성에 영향을 주지 않아야 합니다.
(int | str) == (str | int)
(int | str | float) == typing.Union[str, float, int]
Optional 값은 새로운 유니언 문법과 동등해야 합니다.
None | t == typing.Optional[t]
새로운 Union.__repr__() 메서드가 구현되어야 합니다.
str(int | list[str])
# int | list[str]
str(int | int)
# int
isinstance와 issubclass
Union 항목 자체가 isinstance와 issubclass에 유효한 인자라면, 새로운 문법은 isinstance와 issubclass 호출에서도 허용되어야 합니다.
# valid
isinstance("", int | str)
# invalid
isinstance(2, list[int]) # TypeError: isinstance() argument 2 cannot be a parameterized generic
isinstance(1, int | list[int])
# valid
issubclass(bool, int | float)
# invalid
issubclass(bool, bool | list[int])
호환되지 않는 변경 사항
일부 상황에서는 일부 예외가 예상대로 발생하지 않습니다.
메타클래스가 __or__ 연산자를 구현하면, 그 구현이 이 동작을 재정의합니다:
>>> class M(type):
... def __or__(self, other): return "Hello"
...
>>> class C(metaclass=M): pass
...
>>> C | int
'Hello'
>>> int | C
typing.Union[int, __main__.C]
>>> Union[C, int]
typing.Union[__main__.C, int]
반론과 답변
논의에 대한 자세한 내용은 아래 링크를 참고하십시오:
1. Union[type1, type2]를 위한 새로운 연산자를 추가해야 합니까?
장점:
- 이 문법은 더 읽기 쉬울 수 있으며, 다른 언어(Scala 등)와 유사합니다.
- 3.10에서는 런타임에
int|str표현식이typing을 임포트해서 가져와야 하는 모든 것 대신 단순한 객체를 반환할 수 있습니다
단점:
- 이 연산자를 추가하면
typing과builtins사이에 의존성이 생깁니다 - 백포트가 어려워집니다(
typing은 쉽게 백포트할 수 있지만 핵심types는 그럴 수 없기 때문입니다) - Python 자체를 변경할 필요가 없더라도 mypy, Pyre, PyCharm, Pytype 및 그 밖의 여러 도구에서 이를 구현해야 합니다(“참조 구현”에서 보듯이 사소한 변경입니다).
2. type1 | type2 문법을 허용하도록 PEP 484(타입 힌트)만 변경하는 것은 어떻습니까?
어노테이션의 동적 평가(eval())와 호환되지 않는 것을 받아들인다면, PEP 563 (어노테이션의 지연된 평가)만으로도 이 제안을 수용하기에 충분합니다.
>>> from __future__ import annotations
>>> def foo() -> int | str: pass
...
>>> eval(foo.__annotations__['return'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'type' and 'type'
3. Union을 허용하도록 isinstance()와 issubclass()를 확장하는 것은 어떻습니까?
isinstance(x, str | int) ==> "is x an instance of str or int"
장점:
- 이를 허용한다면 인스턴스 검사에 매우 깔끔해 보이는 표기법을 사용할 수 있습니다
단점:
typing모듈 전체를builtin으로 옮겨야 합니다
참조 구현
t1 | t2의 반환값을 담을 새로운 내장 Union 타입을 구현해야 하며, 이 타입은 isinstance()와 issubclass()에서 지원되어야 합니다. 이 타입은 types 모듈에 둘 수 있습니다. types.Union과 typing.Union 사이의 상호 운용성을 제공해야 합니다.
Python 언어가 확장되면 mypy [1]와 다른 타입 검사기도 이 새로운 문법을 허용하도록 갱신되어야 합니다.
참고 문헌
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.