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

Python 개선 제안 한국어 번역

PEP 436 – Argument Clinic DSL

Author:
Larry Hastings <larry at hastings.org>
Discussions-To:
Python-Dev list
Status:
Final
Type:
Standards Track
Created:
22-Feb-2013
Python-Version:
3.4

Table of Contents

번역·라이선스 안내

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

초록

이 문서는 CPython 구현에서 내장 함수의 인자 처리를 용이하게 하기 위한 DSL인 “Argument Clinic”을 제안합니다.

근거 및 목표

Python의 주요 구현체인 “CPython”은 Python과 C를 혼합하여 작성되었습니다. CPython의 구현에는 “내장” 함수라고 부르는 함수가 있습니다. 이러한 함수는 Python 프로그램에서 사용할 수 있지만 C로 작성되어 있습니다. Python 프로그램이 내장 함수를 호출하고 인자를 전달하면, 해당 인자를 Python 값에서 C 값으로 변환해야 합니다. 이 과정을 “인자 구문 분석”이라고 합니다.

CPython 3.3부터 내장 함수는 거의 항상 다음 두 함수 중 하나를 사용하여 인자를 구문 분석합니다. 원래의 PyArg_ParseTuple(), [1] 그리고 더 현대적인 PyArg_ParseTupleAndKeywords()입니다. [2] 전자는 위치 매개변수만 처리하고, 후자는 키워드 매개변수와 키워드 전용 매개변수도 지원하며 새 코드에 선호됩니다.

어느 함수를 사용하든 호출자는 “형식 문자열”을 통해 인자 구문 분석을 위한 변환을 지정합니다. [3] 각 매개변수는 “형식 단위”에 대응하며, 형식 단위는 구문 분석 함수에 어떤 Python 형식을 허용하고 해당 매개변수에 적합한 C 값으로 어떻게 변환할지를 알려 주는 짧은 문자 시퀀스입니다.

PyArg_ParseTuple()은 처음 고안되었을 때는 합리적이었습니다. 당시에는 이러한 “형식 단위”가 열두 개 정도뿐이었으며, 각각 서로 구별되었고 이해하고 기억하기 쉬웠습니다. 그러나 수년에 걸쳐 PyArg_Parse 인터페이스는 여러 방식으로 확장되었습니다. 현대적인 API는 복잡하여 사용하기가 다소 고통스러울 정도입니다. 다음을 살펴보십시오.

  • 이제 서로 다른 “형식 단위”가 마흔 개나 되며, 그중 일부는 길이가 세 문자에 이릅니다. 이 때문에 프로그래머는 문서를 계속 대조하지 않고서는 형식 문자열이 무엇을 의미하는지, 심지어 형식 문자열을 해석할 수 있는지조차 이해하기 어렵습니다.
  • 형식 문자열 안에 묻혀 있을 수 있는 메타 형식 단위도 여섯 개나 있습니다. (다음과 같습니다: "()|$:;".)
  • 형식 단위가 추가될수록 구현자는 해당 형식 단위에 사용하기 쉬운 니모닉을 선택하기 어려워집니다. 선택하려는 문자가 이미 사용 중일 가능성이 높기 때문입니다. 다시 말해, 형식 단위가 많아질수록 형식 단위는 더욱 난해해집니다.
  • 여러 형식 단위는 미묘한 차이만 있을 뿐 다른 형식 단위와 거의 동일합니다. 이 때문에 형식 문자열의 정확한 의미를 이해하기가 더욱 어려워지고, 정확히 어떤 형식 단위를 원하는지 알아내기도 어려워질 수 있습니다.
  • 독스트링은 정적인 C 문자열로 지정되므로 C 문자열 인용 규칙을 따라야 하며, 이 때문에 읽고 편집하기가 약간 번거롭습니다.
  • PyArg_ParseTupleAndKeywords()를 사용하는 함수에 새 매개변수를 추가할 때는 코드에서 서로 다른 여섯 곳을 수정해야 합니다. [4]
    • 인자를 저장할 변수를 선언합니다.
    • PyArg_ParseTupleAndKeywords()에서 해당 변수에 대한 포인터를 올바른 위치에 전달하고, “길이” 또는 “변환기” 인자가 있다면 올바른 순서로 함께 전달합니다.
    • PyArg_ParseTupleAndKeywords()에 전달되는 “키워드” 배열의 올바른 위치에 인자 이름을 추가합니다.
    • 형식 문자열의 올바른 위치에 형식 단위를 추가합니다.
    • 독스트링의 프로토타입에 매개변수를 추가합니다.
    • 독스트링에 매개변수를 문서화합니다.
  • 현재 내장 함수가 자신의 “시그니처” 정보를 제공할 수 있는 메커니즘은 없습니다(inspect.getfullargspecinspect.Signature 참조). 기존 PyArg_Parse 함수와 유사한 메커니즘을 사용하여 이 정보를 추가하려면 또다시 같은 내용을 반복해서 작성해야 합니다.

이 API를 이러한 단점이 전혀 없는 메커니즘으로 대체하는 것이 Argument Clinic의 목표입니다:

  • 각 매개변수를 한 번만 지정하면 됩니다.
  • 매개변수에 관한 모든 정보가 한곳에 함께 유지됩니다.
  • 각 매개변수에 대해 변환 함수를 지정하면 Argument Clinic이 Python 값에서 C 값으로의 변환을 대신 처리합니다.
  • Argument Clinic은 매개변수화된 변환 함수를 사용하여 인자 처리 동작을 세밀하게 조정할 수도 있게 합니다.
  • 독스트링은 일반 텍스트로 작성합니다. 함수 독스트링은 필수이며, 매개변수별 독스트링을 작성하는 것이 권장됩니다.
  • 이를 바탕으로 Argument Clinic은 CPython이 내부적으로 필요로 하는 모든 단조롭고 반복적인 코드와 데이터 구조를 대신 생성합니다. 인터페이스를 지정한 다음 단계는 네이티브 C 타입을 사용하여 구현을 작성하는 것뿐입니다. 인자 구문의 모든 세부 사항은 대신 처리됩니다.

Argument Clinic은 전처리기로 구현됩니다. Argument Clinic은 Ned Batchelder가 만든 [Cog]로부터 워크플로에 대한 영감을 직접 얻었습니다. Clinic을 사용하려면 특수한 텍스트 문자열로 시작하고 끝나는 블록 주석을 C 소스 코드에 추가한 다음, 파일에서 Clinic을 실행하십시오. Clinic은 블록 주석을 찾아 그 내용을 처리한 후, 주석 바로 다음에 출력을 C 소스 파일에 다시 작성합니다. Clinic의 출력이 소스 코드의 일부가 되도록 하는 것이 의도이며, 이는 버전 관리에 커밋되고 소스 패키지와 함께 배포됩니다. 이는 Python이 계속해서 바로 빌드할 수 있는 상태로 제공된다는 의미입니다. 개발이 약간 복잡해집니다. Clinic을 사용하여 새 함수를 추가하거나 기존 함수의 인자 또는 문서를 수정하려면 작동하는 Python 3 인터프리터가 필요합니다.

Argument Clinic의 향후 목표는 다음과 같습니다:

  • 내장 함수에 대한 시그니처 정보를 제공합니다.
  • Python의 대체 구현이 자동화된 라이브러리 호환성 테스트를 만들 수 있게 합니다.
  • 생성된 코드를 개선하여 인자 구문 분석 속도를 높입니다.

DSL 구문 요약

Argument Clinic DSL은 다음과 같이 C 파일에 삽입된 주석으로 지정합니다. 오른쪽의 “Example” 열에는 Argument Clinic DSL의 샘플 입력이 표시되고, 왼쪽의 “Section” 열에는 각 줄이 차례로 나타내는 내용이 지정됩니다.

Argument Clinic의 DSL 구문은 Python의 def 문을 본떠서 만들었으므로 Python 핵심 개발자에게 어느 정도 익숙합니다.

+-----------------------+-----------------------------------------------------------------+
| Section               | Example                                                         |
+-----------------------+-----------------------------------------------------------------+
| Clinic DSL start      | /*[clinic]                                                      |
| Module declaration    | module module_name                                              |
| Class declaration     | class module_name.class_name                                    |
| Function declaration  | module_name.function_name  -> return_annotation                 |
| Parameter declaration |       name : converter(param=value)                             |
| Parameter docstring   |           Lorem ipsum dolor sit amet, consectetur               |
|                       |           adipisicing elit, sed do eiusmod tempor               |
| Function docstring    | Lorem ipsum dolor sit amet, consectetur adipisicing             |
|                       | elit, sed do eiusmod tempor incididunt ut labore et             |
| Clinic DSL end        | [clinic]*/                                                      |
| Clinic output         | ...                                                             |
| Clinic output end     | /*[clinic end output:<checksum>]*/                              |
+-----------------------+-----------------------------------------------------------------+

제안된 DSL 구문의 형태를 보여 드리기 위해 몇 가지 Clinic 코드 블록 예를 여기 제시합니다. 이 첫 번째 블록은 매개변수 사이의 빈 줄과 인자별 독스트링을 포함하여 일반적으로 선호되는 스타일을 반영합니다. 또한 로컬에서 생성된 사용자 정의 변환기(path_t)도 포함합니다.:

/*[clinic]
os.stat as os_stat_fn -> stat result

   path: path_t(allow_fd=1)
       Path to be examined; can be string, bytes, or open-file-descriptor int.

   *

   dir_fd: OS_STAT_DIR_FD_CONVERTER = DEFAULT_DIR_FD
       If not None, it should be a file descriptor open to a directory,
       and path should be a relative string; path will then be relative to
       that directory.

   follow_symlinks: bool = True
       If False, and the last element of the path is a symbolic link,
       stat will examine the symbolic link itself instead of the file
       the link points to.

Perform a stat system call on the given path.

{parameters}

dir_fd and follow_symlinks may not be implemented
  on your platform.  If they are unavailable, using them will raise a
  NotImplementedError.

It's an error to use dir_fd or follow_symlinks when specifying path as
  an open file descriptor.

[clinic]*/

이 두 번째 예는 모든 매개변수 독스트링과 중요하지 않은 빈 줄을 생략한 최소한의 Clinic 코드 블록을 보여 줍니다.:

/*[clinic]
os.access
   path: path
   mode: int
   *
   dir_fd: OS_ACCESS_DIR_FD_CONVERTER = 1
   effective_ids: bool = False
   follow_symlinks: bool = True
Use the real uid/gid to test for access to a path.
Returns True if granted, False otherwise.

{parameters}

dir_fd, effective_ids, and follow_symlinks may not be implemented
  on your platform.  If they are unavailable, using them will raise a
  NotImplementedError.

Note that most operations will use the effective uid/gid, therefore this
  routine can be used in a suid/sgid environment to test if the invoking user
  has the specified access to the path.

[clinic]*/

이 마지막 예는 왼쪽의 매개변수를 포함하여 선택적 매개변수 그룹을 처리하는 Clinic 코드 블록을 보여 줍니다.:

/*[clinic]
curses.window.addch

   [
   y: int
     Y-coordinate.

   x: int
     X-coordinate.
   ]

   ch: char
     Character to add.

   [
   attr: long
     Attributes for the character.
   ]

   /

Paint character ch at (y, x) with attributes attr,
overwriting any character previously painter at that location.
By default, the character position and attributes are the
current settings for the window object.
[clinic]*/

Argument Clinic DSL의 일반적인 동작

모든 줄은 docstrings를 제외하고 #을 줄 주석 구분자로 지원합니다. 빈 줄은 항상 무시됩니다.

Python 자체와 마찬가지로, Argument Clinic DSL에서는 앞쪽 공백이 중요합니다. “function” 섹션의 첫 번째 줄은 함수 선언입니다. 함수 선언 아래의 들여쓰기된 줄은 한 줄에 하나씩 매개변수를 선언하며, 그보다 더 깊게 들여쓰기된 줄은 매개변수별 docstring입니다. 마지막으로 열 0까지 들여쓰기가 되돌아간 첫 번째 줄에서 매개변수 선언이 끝나고 함수 docstring이 시작됩니다.

매개변수 docstring은 선택 사항이지만 함수 docstring은 필수입니다. 인자를 지정하지 않는 함수는 함수 선언 다음에 docstring만 지정할 수 있습니다.

모듈 및 클래스 선언

C 파일이 모듈이나 클래스를 구현하는 경우 이를 Clinic에 선언해야 합니다. 구문은 간단합니다.:

module module_name

또는

class module_name.class_name

(이것들은 실제로 특수 구문이 아니라 Directives로 구현됩니다.)

모듈 이름이나 클래스 이름은 항상 최상위 모듈부터 시작하는 전체 점 표기 경로여야 합니다. 중첩된 모듈과 클래스가 지원됩니다.

함수 선언

함수 선언의 전체 형식은 다음과 같습니다.:

dotted.name [ as legal_c_id ] [ -> return_annotation ]

점 표기 이름은 최상위 패키지부터 시작하는 함수의 전체 이름이어야 합니다(예: “os.stat” 또는 “curses.window.addch”).

“as legal_c_id” 구문은 선택 사항입니다. Argument Clinic은 함수 이름을 사용하여 생성되는 C 함수의 이름을 만듭니다. 일부 상황에서는 생성된 이름이 C 프로그램의 네임스페이스에 있는 다른 전역 이름과 충돌할 수 있습니다. “as legal_c_id” 구문을 사용하면 생성된 이름을 사용자가 지정한 이름으로 재정의할 수 있습니다. “legal_c_id”를 적법한 C 식별자로 바꾸십시오. 생략하는 경우 “as” 키워드도 생략해야 합니다.

반환 어노테이션도 선택 사항입니다. 생략하는 경우 화살표(”->”)도 생략해야 합니다. 지정하는 경우 반환 어노테이션의 값은 ast.literal_eval과 호환되어야 하며, return converter로 해석됩니다.

매개변수 선언

매개변수 선언 줄의 전체 형식은 다음과 같습니다.:

name: converter [ (parameter=value [, parameter2=value2]) ] [ = default]

“name”은 적법한 C 식별자여야 합니다. 이름과 콜론 사이에는 공백을 사용할 수 있습니다(다만 권장되는 스타일은 아닙니다). 콜론과 변환기 사이에는 공백을 사용할 수 있으며, 공백을 사용하는 것이 권장됩니다.

“converter”는 Argument Clinic에 등록된 “converter functions” 중 하나의 이름입니다. Clinic에는 여러 내장 변환기가 함께 제공되며, 새 변환기도 동적으로 추가할 수 있습니다. 변환기를 선택하면 입력에 허용되는 Python 타입을 자동으로 제한하고, 출력 변수(또는 변수들)의 타입을 지정하게 됩니다. 많은 변환기의 이름이 C 타입이나 Python 타입의 이름과 비슷하지만, 변환기의 이름은 유효한 Python 식별자라면 무엇이든 될 수 있습니다.

변환기 뒤에 괄호가 오면, 이 괄호는 변환 함수에 대한 매개변수를 묶습니다. 이 구문은 Python 함수 호출에 인자를 제공하는 방식과 유사합니다. 매개변수는 항상 이름을 지정해야 하며, 마치 “keyword-only parameters”인 것처럼 작성해야 하고, 매개변수에 제공하는 값은 구문상 Python 리터럴 값과 유사해야 합니다. 이러한 매개변수는 항상 선택 사항이므로 모든 변환 함수를 매개변수 없이 호출할 수 있습니다. 이 경우 괄호를 완전히 생략할 수도 있으며, 이는 항상 빈 괄호를 지정하는 것과 같습니다. 이러한 매개변수에 제공하는 값은 ast.literal_eval과 호환되어야 합니다.

“default”는 Python 리터럴 값입니다. 기본값은 선택 사항이며, 지정하지 않을 경우 등호도 생략해야 합니다. 기본값이 없는 매개변수는 암시적으로 필수 항목입니다. 기본값은 생성된 C 코드에 동적으로 할당되어 “live” 상태로 존재하며, Python 값으로 지정되지만 생성된 C 코드에서는 네이티브 C 값으로 변환됩니다. 이러한 수동 변환 단계 때문에 허용되는 기본값은 많지 않습니다.

이것이 Python 함수 선언이라면, 매개변수 선언은 뒤따르는 쉼표나 닫는 괄호로 구분될 것입니다. 그러나 Argument Clinic은 둘 다 사용하지 않으며, 매개변수 선언은 줄 바꿈으로 구분됩니다. 뒤따르는 쉼표나 닫는 괄호는 허용되지 않습니다.

첫 번째 매개변수 선언이 특정 Clinic 코드 블록의 모든 매개변수 선언에 대한 들여쓰기 수준을 설정합니다. 이후의 모든 매개변수는 동일한 수준으로 들여써야 합니다.

레거시 변환기

기존 코드를 Argument Clinic으로 변환하는 편의를 위해 Clinic은 PyArg_ParseTuple 형식 단위와 일치하는 레거시 변환기 집합을 제공합니다. 이 변환기는 형식 단위를 포함하는 C 문자열로 지정합니다. 예를 들어, 매개변수 “foo”가 Python “int”를 받고 C int를 출력하도록 지정하려면 다음과 같이 지정할 수 있습니다.:

foo : "i"

(C 문자열과 더 유사하게 보이도록 하려면 항상 큰따옴표를 사용해야 합니다.)

이것들은 PyArg_ParseTuple 형식 단위와 유사하지만, 구문 분석을 위해 구현에서 PyArg_Parse 함수를 호출한다는 보장은 없습니다.

이 구문은 매개변수를 지원하지 않습니다. 따라서 입력 매개변수가 필요한 형식 단위("O!", "O&", "es", "es#", "et", "et#")는 지원하지 않습니다. 이러한 변환 중 하나가 필요한 매개변수에는 레거시 구문을 사용할 수 없습니다. (그래도 기본값은 제공할 수 있습니다.)

매개변수 독스트링

아래에 나타나며 매개변수 선언보다 더 많이 들여쓴 모든 줄은 해당 매개변수의 독스트링입니다. 이러한 모든 줄은 첫 번째 줄이 왼쪽 끝에 맞춰질 때까지 “dedented”됩니다.

매개변수 줄의 특수 구문

매개변수 섹션에서 사용할 수 있는 특수 기호는 네 가지입니다. 이러한 기호는 각각 한 줄에 단독으로 나타나야 하며, 매개변수 선언과 같은 수준으로 들여쓰기해야 합니다. 네 기호는 다음과 같습니다.

*
이후의 모든 매개변수가 키워드 전용임을 설정합니다.
[
선택적 “그룹”의 시작을 설정합니다. “그룹”은 다른 “그룹” 안에 중첩될 수 있다는 점에 유의하십시오. 아래의 Functions With Positional-Only Parameters을 참조하십시오. 현재 [모든 매개변수가 위치 전용으로 표시된 함수에서만 사용할 수 있다는 점에 유의하십시오. 아래의 /를 참조하십시오.
]
선택적 “그룹”의 끝을 나타냅니다.
/
이후의 모든 인자가 위치 전용임을 설정합니다. 현재 Argument Clinic은 위치 전용 인자와 위치 전용이 아닌 인자를 모두 사용하는 함수를 지원하지 않습니다. 따라서 함수에 /가 지정된 경우, 현재는 항상 마지막 매개변수 뒤에 있어야 합니다. 또한 Argument Clinic은 현재 위치 전용 매개변수의 기본값을 지원하지 않습니다.

(/의 의미는 Guido가 한때 제안한 Python의 위치 전용 매개변수 구문을 따릅니다. [5] )

함수 독스트링

함수 선언 뒤에 선행 공백이 없는 첫 번째 줄이 함수 독스트링의 첫 번째 줄입니다. Clinic 블록의 이후 모든 줄은 독스트링의 일부로 간주되며, 해당 줄의 선행 공백은 보존됩니다.

함수 독스트링 내부에서 {parameters}이 한 줄에 단독으로 나타나면, Argument Clinic은 독스트링이 있는 모든 매개변수의 목록을 삽입하며, 각 매개변수 뒤에 해당 독스트링을 배치합니다. 매개변수 이름은 한 줄에 단독으로 표시되고, 독스트링은 다음 줄에서 시작하며, 독스트링의 모든 줄은 두 칸 들여쓰기됩니다. (매개변수별 독스트링이 없는 매개변수는 제외됩니다.) 전체 목록은 {parameters} 토큰 앞에 있던 선행 공백만큼 들여쓰기됩니다.

독스트링에 {parameters}가 나타나지 않으면 Argument Clinic은 독스트링 끝에 이를 추가하며, 독스트링이 빈 줄로 끝나지 않는 경우 그 위에 빈 줄을 삽입하고, 매개변수 목록은 열 0에 배치합니다.

변환기

Argument Clinic에는 미리 초기화된 변환기 함수 레지스트리가 포함되어 있습니다. 변환기 함수의 예는 다음과 같습니다.

int
__int__를 구현하는 Python 객체를 받아 C int를 생성합니다.
byte
Python int를 받아 unsigned char를 생성합니다. 정수는 [0, 256) 범위에 있어야 합니다.
str
Python str 객체를 받아 C char *를 생성합니다. 문자열을 ascii 코덱을 사용하여 자동으로 인코딩합니다.
PyObject
모든 객체를 허용하며, 변환 없이 C PyObject *를 출력합니다.

모든 변환기는 다음 매개변수를 허용합니다.

doc_default
Python 컨텍스트에서 매개변수의 실제 기본값 대신 사용할 Python 값입니다. 즉, 지정하면 이 값이 문서 문자열과 Signature에서 매개변수의 기본값으로 사용됩니다. (TBD 대체 의미: 문자열이 유효한 Python 표현식이며 eval()을 사용하여 Python 값으로 렌더링할 수 있다면, 해당 문자열에 eval()을 적용한 결과가 Signature의 기본값으로 사용됩니다.) 기본값이 없으면 무시합니다.
required
일반적으로 기본값이 있는 모든 매개변수는 자동으로 선택 사항이 됩니다. “required”가 설정된 매개변수는 기본값이 있더라도 필수(선택 사항이 아님)로 간주됩니다. 생성된 문서에도 기본값이 표시되지 않습니다.

또한 변환기는 다음 선택적 매개변수 중 하나 이상을 개별적으로 허용할 수 있습니다.

annotation
이 매개변수에 대한 매개변수별 어노테이션을 명시적으로 지정합니다. 일반적으로 어노테이션이 있는 경우 이를 생성하는 책임은 변환 함수에 있습니다.
bitwise
부호 없는 정수를 허용하는 변환기에 사용합니다. 전달된 Python 정수가 부호 있는 경우 음수라도 비트를 직접 복사합니다.
encoding
str을 허용하는 변환기에 사용합니다. 유니코드 문자열을 char *로 인코딩할 때 사용할 인코딩입니다.
immutable
불변 값만 허용합니다.
length
이터러블 유형을 허용하는 변환기에 사용합니다. 변환기가 이터러블의 길이도 출력하도록 요청합니다. 길이는 _impl함수에 Py_ssize_t 변수로 전달되며, 그 이름은 이 매개변수의 이름에 “_length”를 덧붙인 것입니다.
nullable
이 변환기는 일반적으로 None을 허용하지 않지만, 이 경우에는 허용해야 합니다. Python 측에서 None이 제공되면 이에 상응하는 C 인자는 NULL이 됩니다. 이 변환기가 출력하는 _impl인자는 아마도 포인터 유형일 것입니다.
types
이 객체에 허용되는 Python 유형을 나타내는 문자열 목록입니다. 또한 Python 프로토콜을 나타내는 네 개의 문자열이 있습니다.
  • “buffer”
  • “매핑”
  • 숫자
  • 시퀀스
문자
문자열 형식을 허용하는 변환기의 경우입니다. 변환된 값에는 삽입된 널 문자가 포함될 수 있어야 합니다.

반환 변환기

반환 변환기는 개념적으로 변환기의 역연산을 수행합니다. 즉, 네이티브 C 값을 이에 상응하는 Python 값으로 변환합니다.

지시문

Argument Clinic은 Clinic 코드 블록에서 “지시문”도 사용할 수 있도록 합니다. 지시문은 C의 프라그마와 유사하며, Argument Clinic의 동작을 수정하는 문입니다.

지시문의 형식은 다음과 같습니다.:

directive_name [argument [second_argument [ ... ]]]

지시문은 위치 인자만 받습니다.

Clinic 코드 블록에는 하나 이상의 지시문이나 함수 선언 중 하나가 포함되어야 합니다. 둘 다 포함할 수도 있으며, 이 경우 모든 지시문은 함수 선언 앞에 와야 합니다.

지시문은 내부적으로 Python 호출 가능 객체에 직접 매핑됩니다. 지시문의 인자는 str()형식의 위치 인자로 호출 가능 객체에 직접 전달됩니다.

가능한 지시문의 예로는 Clinic 출력의 생성, 억제 또는 리디렉션이 있습니다. 또한 프로토타입에서는 “module” 및 “class” 키워드가 지시문으로 구현되어 있습니다.

Python 코드

Argument Clinic은 C 파일 안에 Python 코드를 삽입할 수도 있으며, Argument Clinic이 파일을 처리할 때 해당 코드를 제자리에서 실행합니다. 삽입된 코드는 다음과 같은 형태입니다.:

/*[python]

# this is python code!
print("/" + "* Hello world! *" + "/")

[python]*/
/* Hello world! */
/*[python end:da39a3ee5e6b4b0d3255bfef95601890afd80709]*/

위의 "/* Hello world! */" 행은 앞의 주석에 있는 Python 코드를 실행하여 생성되었습니다.

모든 Python 코드를 사용할 수 있습니다. Argument Clinic의 Python 코드 섹션을 사용하여 Clinic과 직접 상호 작용할 수도 있습니다. Argument Clinic Programmatic Interfaces를 참조하십시오.

출력

Argument Clinic은 C 파일에 출력 결과를 인라인으로 기록하며, Clinic 코드 섹션 바로 뒤에 기록합니다. “python” 섹션의 경우 출력은 builtins.print를 사용하여 출력된 모든 내용입니다. “clinic” 섹션의 경우 출력은 다음을 포함하는 유효한 C 코드입니다.

  • 함수에 올바른 methoddef 구조를 제공하는 #define
  • “impl” 함수의 프로토타입 – 이 함수의 구현을 위해 작성할 부분입니다.
  • 모든 인자 처리를 담당하고 사용자의 “impl” 함수를 호출하는 함수
  • “impl” 함수의 정의 행
  • 그리고 출력의 끝을 나타내는 주석입니다.

출력 직후에 impl 함수의 본문을 작성한다는 뜻입니다. 즉, 출력 끝 주석 바로 뒤에 왼쪽 중괄호를 작성하고 그 안에서 builtin을 구현합니다. 처음에는 조금 이상하지만, 묘하게 편리합니다.

Argument Clinic이 impl 함수의 매개변수를 대신 정의합니다. 이 함수는 원래 전달된 “self” 매개변수와 사용자가 정의한 모든 매개변수, 그리고 추가로 생성될 수 있는 매개변수(“length” 매개변수 및 다음 절에서 설명할 “group” 매개변수)를 받습니다.

Argument Clinic은 출력 섹션의 체크섬도 작성합니다. 이는 중요한 안전 기능입니다. 출력을 수동으로 수정하면 Clinic이 체크섬이 일치하지 않음을 감지하고 파일을 덮어쓰지 않습니다. (-f 명령줄 인자를 사용하면 Clinic이 강제로 덮어쓰도록 할 수 있으며, -o 명령줄 인자를 사용하면 Clinic은 체크섬도 무시합니다.)

마지막으로 Argument Clinic은 정의된 클래스와 모듈의 PyMethodDef 배열에 대한 상용구 정의도 출력할 수 있습니다.

위치 전용 매개변수를 사용하는 함수

C로 구현된 Python 내장 함수 중 상당수는 인자를 처리할 때 이전의 위치 전용 API(PyArg_ParseTuple()를)를 사용합니다. 일부 경우 이러한 내장 함수는 전달된 인자의 개수에 따라 인자를 서로 다르게 구문 분석합니다. 이로 인해 매우 당혹스러울 정도의 유연성이 제공될 수 있습니다. 즉, 선택적 매개변수 그룹이 있을 수 있으며, 이 그룹은 모두 지정하거나 하나도 지정하지 않아야 합니다. 그리고 때로는 이러한 그룹이 왼쪽에 있습니다! (대표적인 예로 curses.window.addch()가 있습니다.)

Argument Clinic은 매개변수를 그룹으로 지정할 수 있도록 하여 이러한 레거시 사용 사례를 지원합니다. 각 선택적 매개변수 그룹은 대괄호로 표시합니다. 이러한 그룹은 필수 매개변수의 오른쪽이나 왼쪽 어디에든 올 수 있다는 점에 유의하십시오!

Clinic이 생성하는 impl 함수에는 각 그룹마다 추가 매개변수가 하나씩 추가됩니다. 이 매개변수는 “int group_{left|right}_<x>” 형식이며, 여기서 x는 필수 인자에서 멀어지는 방향으로 그룹을 생성하면서 각 그룹에 할당되는 단조 증가 번호입니다. 이 인자는 이번 호출에서 해당 그룹이 지정되었으면 0이 아닌 값이고, 지정되지 않았으면 0입니다.

이 모드로 동작할 때는 기본 인자를 지정할 수 없다는 점에 유의하십시오.

또한 함수에 그룹 집합을 지정할 때 인자 개수에서 유효한 그룹 집합으로의 매핑이 여러 개 가능하도록 만들 수도 있습니다. 이러한 경우 Clinic은 오류 메시지와 함께 중단합니다. 이는 문제가 되지 않아야 합니다. 위치 전용 동작은 레거시 사용 사례만을 위한 것이며, 이러한 특이한 동작을 사용하는 모든 레거시 함수는 모호하지 않은 매핑을 갖기 때문입니다.

현재 상태

이 글을 작성하는 시점에는 Argument Clinic의 작동하는 프로토타입 구현을 온라인에서 사용할 수 있습니다(다만 이 글을 읽을 때는 구문이 오래되었을 수 있습니다). [6] 프로토타입은 기존 PyArg_Parse API를 사용하여 코드를 생성합니다. 이 프로토타입은 수수께끼 같은 "w*"를 제외한 현재의 모든 형식 단위로의 변환을 지원합니다. Argument Clinic을 사용하는 샘플 함수는 위치 전용 인자 구문 분석을 비롯한 모든 주요 기능을 시험합니다.

Argument Clinic 프로그래밍 인터페이스

또한 이 프로토타입은 현재 새로운 형식에 대한 지원을 즉석에서 추가할 수 있는 실험적 확장 메커니즘을 제공합니다. 사용 예는 프로토타입의 Modules/posixmodule.c를 참조하십시오.

향후에는 Python 코드를 통해 함수 선언을 조회하거나 수정하거나 완전히 새로 생성할 수 있을 정도로 Argument Clinic을 자동화할 수 있을 것으로 예상합니다. 심지어 사용자가 직접 만든 DSL을 동적으로 추가할 수도 있을 것입니다!

참고 / TBD

  • 빌트인에 대한 inspect.Signature 메타데이터를 제공하기 위한 API는 현재 논의 중입니다. Argument Clinic은 프로토타입이 실현 가능해지면 이를 지원할 예정입니다.
  • Alyssa Coghlan은 a) 함수당 왼쪽-선택적 그룹을 최대 하나만 지원하고, b) 모호성이 있는 경우 오른쪽 그룹보다 왼쪽 그룹을 우선시할 것을 제안합니다. 이는 range()를 포함한 기존의 모든 사용 사례를 해결할 것입니다.
  • 최적의 경우, Argument Clinic이 일반적인 Python 빌드 프로세스의 일부로 자동 실행되기를 원합니다. 하지만 이는 부트스트래핑 문제를 야기합니다: 시스템에 Python 3가 없다면, Python 3를 빌드하기 위해 Python 3 실행 파일이 필요합니다. 이는 분명 해결 가능한 문제라고 생각하지만, 최선의 해결책이 무엇일지는 모르겠습니다. (이를 지원하려면 Windows용 병행 솔루션도 필요할 것입니다.)
  • 관련하여, inspect.Signature에는 curses.window.addchyx의 왼쪽-선택적 블록과 같은 인자 블록을 표현할 방법이 없습니다. 이 명백히 변칙적인 매개변수 패러다임을 지원하는 데 있어 우리는 어디까지 나아갈 것입니까?
  • PyCon US 2013 Language Summit 동안, Argument Clinic이 함수에 대한 실제 문서(ReST 형식으로 작성되어 Sphinx로 처리됨)도 생성하도록 하자는 논의가 있었습니다. 이에 대한 구체적인 방식은 아직 정해지지 않았지만, docstring이 ReST로 작성되어야 하고 Python이 ReST -> ascii 변환기를 함께 제공해야 할 것입니다. CPython 소스 트리를 Clinic을 사용하도록 대규모로 전환하기 전에 이에 대한 결정을 내리는 것이 가장 좋을 것입니다.
  • Guido는 “함수 docstring”을 출력 중간에 직접 손으로 작성하는 방식을 다음과 같이 제안했습니다:
    /*[clinic]
      ... prototype and parameters (including parameter docstrings) go here
    [clinic]*/
    ... some output ...
    /*[clinic docstring start]*/
    ... hand-edited function docstring goes here   <-- you edit this by hand!
    /*[clinic docstring end]*/
    ... more output
    /*[clinic output end]*/
    

    이 방식을 시도해 보았지만 마음에 들지 않습니다 – 다소 어설프다고 생각합니다. DSL 출력 중간에 수동으로 편집한 부분이 섬처럼 존재하는 것보다는, 작성하는 모든 것이 한 곳에 모이는 편을 선호합니다.

  • Argument Clinic은 자동 튜플 언패킹(PyArg_ParseTuple()을 위한 “(OOO)” 스타일 형식 문자열)을 지원하지 않습니다.
  • Argument Clinic은 동적 특성/유연성을 일부 제거합니다. PyArg_ParseTuple()을 사용하면 이론적으로 “es”/”et” 형식 단위에 대해 런타임에 서로 다른 인코딩을 전달할 수 있었습니다. 제가 아는 한 CPython 자체는 이렇게 하지 않지만, 외부 사용자가 이렇게 할 가능성은 있습니다. (여담: regrtest에서 실행되는 “es”의 사용례는 없으며, 실행되는 “et”의 사용례는 모두 socketmodule.c에 있고 _ssl.c에 있는 것 하나만 예외입니다. 이들은 모두 정적이며, 인코딩 "idna"를 지정합니다.)

감사의 말

PEP 작성자는 Cog―”제가 한 번도 써 본 적 없는 가장 좋아하는 도구”―에 대한 그의 영리한 설계를 뻔뻔하게 베낄 수 있도록 허락해 준 Ned Batchelder에게 감사드립니다. [bugtracker issue]와 python-dev에서 피드백을 준 모든 분들께도 감사드립니다. 2013년 PyCon US에서 이 주제에 대해 두 시간 동안 열띤 대면 토론을 나눠 준 Alyssa(Nick) Coghlan과 Guido van Rossum에게 특별히 감사드립니다.

참고 문헌