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

Python 개선 제안 한국어 번역

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

Table of Contents

번역·라이선스 안내

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

Important

This PEP is a historical document. The up-to-date, canonical documentation can now be found at Union Type.

×

See PEP 1 for how to propose changes.

초록

이 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]와 다른 타입 검사기도 이 새로운 문법을 허용하도록 갱신되어야 합니다.

참고 문헌