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

Python 개선 제안 한국어 번역

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의 함수 어노테이션에 관한 정확한 세부 사항을 논의하기 전에, 먼저 어노테이션이 무엇이며 무엇이 아닌지 폭넓게 살펴보겠습니다:

  1. 매개변수와 반환값에 대한 함수 어노테이션은 모두 완전히 선택 사항입니다.
  2. 함수 어노테이션은 컴파일 시점에 임의의 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:
        ...
    

    그러나 첫 번째 예제의 문자열과 두 번째 예제의 타입 정보는 어느 것도 그 자체로 의미를 갖지 않으며, 의미는 오직 서드파티 라이브러리에서 비롯됩니다.

  3. 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].

  1. 이는 호환되지 않는 변경이 될 것입니다.
  2. 어차피 람다는 기능이 제한되어 있습니다.
  3. 람다는 언제든지 함수로 변경할 수 있습니다.

함수 어노테이션에 액세스하기

컴파일된 후에는 함수의 어노테이션을 함수의 __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__는 비어 있는 변경 가능한 딕셔너리입니다.

사용 사례

어노테이션을 논의하는 과정에서 여러 사용 사례가 제기되었습니다. 이러한 사례 중 일부를 전달하는 정보의 종류에 따라 그룹으로 묶어 여기에서 소개합니다. 어노테이션을 활용할 수 있는 기존 제품과 패키지의 예도 포함되어 있습니다.

  • 타입 정보 제공
    • 타입 검사 ([3], [4])
    • IDE에서 함수가 기대하고 반환하는 타입을 표시하도록 하기 ([16])
    • 함수 오버로딩 / 제네릭 함수 ([21])
    • 외국어 브리지 ([17], [18])
    • 적용 ([20], [19])
    • 술어 논리 함수
    • 데이터베이스 쿼리 매핑
    • RPC 매개변수 마샬링 ([22])
  • 기타 정보
    • 매개변수 및 반환 값에 대한 문서 ([23])

표준 라이브러리

pydoc 및 inspect

pydoc 모듈은 함수에 대한 도움말을 표시할 때 함수 어노테이션을 표시해야 합니다. inspect 모듈은 어노테이션을 지원하도록 변경되어야 합니다.

다른 PEP와의 관계

함수 시그니처 객체 (PEP 362)

함수 시그니처 객체는 함수의 어노테이션을 노출해야 합니다. Parameter 객체는 변경될 수 있으며, 다른 변경이 필요할 수도 있습니다.

구현

참조 구현이 py3k(이전에는 “p3yk”) 브랜치에 리비전 53170으로 체크인되었습니다 ([10]).

거부된 제안

  • BDFL은 제너레이터에 어노테이션을 추가하기 위한 특수 구문에 대한 저자의 아이디어를 “너무 보기 흉하다”는 이유로 거부했습니다 ([2]).
  • 초기에 논의되었지만 ([5], [6]), 제너레이터 함수와 고차 함수에 어노테이션을 지정하기 위한 특수 객체를 표준 라이브러리에 포함하는 것은 서드파티 라이브러리에 더 적합하다는 이유로 결국 거부되었습니다. 이를 표준 라이브러리에 포함하면 너무 많은 까다로운 문제가 발생했습니다.
  • 표준 타입 매개변수화 구문에 대한 상당한 논의가 있었음에도, 이 역시 서드파티 라이브러리에 맡겨야 한다고 결정되었습니다. ([7], [8], [9]).
  • 어노테이션 상호 운용성을 위한 메커니즘을 표준화하지 않기로 결정되었으며, 이에 대해서는 더 많은 논의가 있었습니다. 이 시점에서 상호 운용성 규칙을 표준화하는 것은 시기상조였을 것입니다. 모든 사용자를 어떤 인위적인 방식에 억지로 끼워 맞추기보다는, 실제 사용과 필요성에 기반하여 이러한 규칙이 자연스럽게 발전하도록 하는 편이 낫다고 판단했습니다. ([13], [14], [15]).

참고 문헌 및 각주