PEP 3107 – 함수 어노테이션
- Author:
- Collin Winter <collinwinter at google.com>, Tony Lownds <tony at lownds.com>
- Status:
- Final
- Type:
- Standards Track
- Created:
- 02-Dec-2006
- Python-Version:
- 3.0
- Post-History:
Table of Contents
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 Python 함수에 임의의 메타데이터 어노테이션을 추가하는 문법을 도입합니다 [1].
근거
Python 2.x 시리즈에는 함수의 매개변수와 반환값에 어노테이션을 다는 표준 방법이 없기 때문에, 이 공백을 메우기 위해 다양한 도구와 라이브러리가 등장했습니다. 일부는 PEP 318에서 도입된 데코레이터를 활용하고, 다른 일부는 함수의 독스트링을 파싱하여 그 안에서 어노테이션을 찾습니다.
이 PEP는 이러한 정보를 지정하는 단일한 표준 방법을 제공하여, 지금까지 메커니즘과 문법이 제각각이어서 생긴 혼란을 줄이는 것을 목표로 합니다.
함수 어노테이션의 기본 개념
Python 3.0 함수 어노테이션의 세부 사항을 정확히 논의하기에 앞서, 먼저 어노테이션이 무엇이고 무엇이 아닌지를 폭넓게 이야기해 봅시다:
- 함수 어노테이션은 매개변수에 대한 것이든 반환값에 대한 것이든 완전히 선택 사항입니다.
- 함수 어노테이션은 컴파일 시점에 임의의 Python 표현식을 함수의 여러 부분에 연결하는 방법일 뿐입니다.
Python은 그 자체로는 어노테이션에 어떠한 특별한 의미나 중요성도 부여하지 않습니다. Python은 그대로 두면 이 표현식들을 아래 Accessing Function Annotations에서 설명한 대로 접근할 수 있게 할 뿐입니다.
어노테이션이 의미를 갖게 되는 유일한 경우는 서드파티 라이브러리가 이를 해석할 때입니다. 이러한 어노테이션 소비자는 함수의 어노테이션으로 원하는 무엇이든 할 수 있습니다. 예를 들어, 어떤 라이브러리는 다음과 같이 문자열 기반 어노테이션을 사용하여 개선된 도움말 메시지를 제공할 수 있습니다:
def compile(source: "something compilable", filename: "where the compilable thing comes from", mode: "is this a single statement or a suite?"): ...
또 다른 라이브러리는 Python 함수와 메서드에 타입 검사를 제공하는 데 사용될 수 있습니다. 이 라이브러리는 어노테이션을 사용하여 함수가 기대하는 입력 타입과 반환 타입을 나타낼 수 있으며, 아마도 다음과 같은 형태가 될 것입니다:
def haul(item: Haulable, *vargs: PackAnimal) -> Distance: ...
그러나 첫 번째 예제의 문자열도, 두 번째 예제의 타입 정보도 그 자체로는 아무런 의미가 없습니다. 의미는 오로지 서드파티 라이브러리에서 비롯됩니다.
- 2번 항목에 따라, 이 PEP는 내장 타입에 대해서조차 어떠한 종류의 표준 의미 체계도 도입하려 하지 않습니다. 이 작업은 서드파티 라이브러리에 맡깁니다.
문법
매개변수
매개변수에 대한 어노테이션은 매개변수 이름 뒤에 오는 선택적 표현식의 형태를 취합니다:
def foo(a: expression, b: expression = 5):
...
의사 문법으로 표현하면, 이제 매개변수는 identifier [: expression] [= expression]과 같은 형태가 됩니다. 즉, 어노테이션은 항상 매개변수의 기본값보다 앞에 오며, 어노테이션과 기본값은 모두 선택 사항입니다. 등호가 기본값을 나타내는 데 사용되는 것과 마찬가지로, 콜론은 어노테이션을 표시하는 데 사용됩니다. 모든 어노테이션 표현식은 기본값과 마찬가지로 함수 정의가 실행될 때 평가됩니다.
초과 매개변수(즉, *args와 **kwargs)에 대한 어노테이션도 비슷한 방식으로 나타냅니다:
def foo(*args: expression, **kwargs: expression):
...
중첩된 매개변수에 대한 어노테이션은 항상 마지막 괄호가 아니라 매개변수 이름 뒤에 옵니다. 중첩된 매개변수에 속한 모든 매개변수에 어노테이션을 달 필요는 없습니다:
def foo((x1, y1: expression),
(x2: expression, y2: expression)=(None, None)):
...
반환값
지금까지의 예제에서는 함수 반환값의 타입에 어노테이션을 다는 방법을 보여 주지 않았습니다. 이는 다음과 같이 합니다.:
def sum() -> expression:
...
즉, 이제 매개변수 목록 뒤에 리터럴 ->와 Python 표현식이 올 수 있습니다. 매개변수에 대한 어노테이션과 마찬가지로, 이 표현식은 함수 정의가 실행될 때 평가됩니다.
이제 함수 정의의 문법 [11]은 다음과 같습니다.:
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ['->' test] ':' suite
parameters: '(' [typedargslist] ')'
typedargslist: ((tfpdef ['=' test] ',')*
('*' [tname] (',' tname ['=' test])* [',' '**' tname]
| '**' tname)
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
tname: NAME [':' test]
tfpdef: tname | '(' tfplist ')'
tfplist: tfpdef (',' tfpdef)* [',']
람다
lambda의 문법은 어노테이션을 지원하지 않습니다. 매개변수 목록을 괄호로 감싸도록 요구하면 lambda의 문법을 어노테이션을 지원하도록 변경할 수 있습니다. 그러나 다음과 같은 이유로 이 변경은 하지 않기로 결정되었습니다 [12]:
- 호환되지 않는 변경이 됩니다.
- 람다는 어차피 기능이 제한되어 있습니다.
- 람다는 언제든 함수로 바꿀 수 있습니다.
함수 어노테이션에 접근하기
컴파일되고 나면 함수의 어노테이션은 함수의 __annotations__ 속성을 통해 사용할 수 있습니다. 이 속성은 매개변수 이름을 평가된 어노테이션 표현식을 나타내는 객체에 매핑하는 변경 가능한 딕셔너리입니다
__annotations__ 매핑에는 "return"이라는 특별한 키가 있습니다. 이 키는 함수의 반환값에 어노테이션이 주어진 경우에만 존재합니다.
예를 들어, 다음 어노테이션은:
def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
...
다음과 같은 __annotations__ 매핑을 만들어 냅니다.
{'a': 'x',
'b': 11,
'c': list,
'return': 9}
return 키를 선택한 이유는 매개변수 이름과 충돌할 수 없기 때문입니다. return을 매개변수 이름으로 사용하려고 하면 SyntaxError가 발생합니다.
함수에 어노테이션이 없거나 함수가 lambda 표현식으로 만들어진 경우 __annotations__는 비어 있는 변경 가능한 딕셔너리입니다.
사용 사례
어노테이션을 논의하는 과정에서 여러 사용 사례가 제기되었습니다. 그중 일부를 전달하는 정보의 종류별로 묶어 여기에 소개합니다. 어노테이션을 활용할 수 있는 기존 제품과 패키지의 예도 함께 실었습니다.
표준 라이브러리
pydoc과 inspect
pydoc 모듈은 함수의 도움말을 표시할 때 함수 어노테이션을 표시해야 합니다. inspect 모듈은 어노테이션을 지원하도록 변경되어야 합니다.
다른 PEP와의 관계
함수 시그니처 객체 (PEP 362)
함수 시그니처 객체는 함수의 어노테이션을 노출해야 합니다. Parameter 객체가 변경될 수도 있고, 다른 변경이 필요할 수도 있습니다.
구현
참조 구현이 py3k(이전 명칭 “p3yk”) 브랜치에 리비전 53170으로 체크인되었습니다 [10].
거부된 제안
- BDFL은 제너레이터에 어노테이션을 추가하기 위한 특수 문법이라는 저자의 아이디어를 “너무 보기 흉하다”는 이유로 거부했습니다 [2].
- 초기에 논의되기는 했지만 ([5], [6]), 제너레이터 함수와 고차 함수에 어노테이션을 달기 위한 특수 객체를 stdlib에 포함하는 것은 서드파티 라이브러리에 더 적합하다는 이유로 최종적으로 거부되었습니다. 이를 표준 라이브러리에 포함하면 까다로운 문제가 너무 많이 발생했습니다.
- 표준 타입 매개변수화 문법에 대해 상당한 논의가 있었지만, 이 역시 서드파티 라이브러리에 맡기기로 결정했습니다. ([7], [8], [9]).
- 더 많은 논의가 있었음에도 불구하고, 어노테이션 상호 운용성을 위한 메커니즘은 표준화하지 않기로 결정했습니다. 현시점에서 상호 운용성 규약을 표준화하는 것은 시기상조일 것입니다. 모든 사용자에게 어떤 인위적인 체계를 강요하기보다는, 실제 사용과 필요에 따라 이러한 규약이 자연스럽게 발전하도록 두고자 합니다. ([13], [14], [15]).
참고 문헌 및 각주
Copyright
This document has been placed in the public domain.