PEP 614 – 데코레이터의 문법 제한 완화
- Author:
- Brandt Bucher <brandt at python.org>
- Sponsor:
- Guido van Rossum <guido at python.org>
- Status:
- Final
- Type:
- Standards Track
- Created:
- 10-Feb-2020
- Python-Version:
- 3.9
- Post-History:
- 11-Feb-2020, 18-Feb-2020, 03-Mar-2020
- Resolution:
- Python-Dev thread
Table of Contents
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
현재 Python에서는 모든 데코레이터가 점으로 구분된 이름으로 구성되고, 선택적으로 단일 호출이 뒤따라야 합니다. 이 PEP에서는 이러한 제한을 제거하고 데코레이터가 유효한 모든 표현식이 될 수 있도록 제안합니다.
동기
데코레이터가 처음 도입되었을 때, Guido가 설명한 것처럼 문법을 제한한 동기는 기술적 요구 사항이 아니라 선호였습니다:
이 문제에 대해서는 직감적으로 느끼는 바가 있습니다. 그것이 어디에서 비롯된 것인지는 확실하지 않지만, 그런 느낌이 있습니다… 따라서 앞으로 문법을@test로 변경하는 것은 상당히 쉽겠지만,@test를 허용하면 가독성이 향상되는 실제 사용 사례가 제시되지 않는 한 더 제한적인 형식을 고수하고 싶습니다.
이러한 제한은 실제로 거의 마주치지 않았지만, 수년에 걸쳐 제한을 제거해 달라는 BPO 이슈와 메일링 리스트 게시물이 지속적으로 제기되었습니다. 가장 최근의 사례 (이 사례가 이 제안의 계기가 되었습니다)에는 PyQt5 라이브러리를 사용하는 코드의 좋은 예가 포함되어 있었으며, 기존 제한을 완화하면 이 코드는 더 읽기 쉽고 관용적이며 유지 관리하기 쉬워질 것입니다. 약간 수정하면 다음과 같습니다.:
buttons = [QPushButton(f'Button {i}') for i in range(10)]
# Do stuff with the list of buttons...
@buttons[0].clicked.connect
def spam():
...
@buttons[1].clicked.connect
def eggs():
...
# Do stuff with the list of buttons...
현재 이러한 데코레이션은 다음과 비슷한 형태로 다시 작성해야 합니다.:
button_0 = buttons[0]
@button_0.clicked.connect
def spam():
...
button_1 = buttons[1]
@button_1.clicked.connect
def eggs():
...
또한 현재 문법은 이미 충분히 느슨하므로 더 복잡한 데코레이터 표현식을 조합하는 것은 사소한 일입니다. 따라서 의도한 대로 임의로 복잡한 표현식을 금지하기보다는, 현재의 제한이 표현식을 더 보기 흉하고 비효율적으로 만들 뿐입니다.:
# Identity function hack:
def _(x):
return x
@_(buttons[0].clicked.connect)
def spam():
...
# eval hack:
@eval("buttons[1].clicked.connect")
def eggs():
...
근거
모든 표현식 허용
모든 유효한 표현식을 허용하자는 결정은 (예를 들어 첨자 표기를 허용하도록 현재 제한을 완화하는 데 그치지 않고) 오랫동안 데코레이터 문법 진화의 다음 논리적 단계로 고려되어 왔습니다. 또 다른 메일링 리스트 스레드에서 Guido가 지적했듯이:
일반 표현식보다 더 제한적이면서 현재보다 덜 제한적인 형태로 만드는 것은 합리적이지 않다고 생각합니다.
문법에 특례를 두어 일부 유용한 경우를 허용하더라도 현재 상황을 복잡하게 만들 뿐이며, 머지않아 언젠가 그 과정이 반복될 것이 거의 확실합니다. 또한 이 문법 변경의 목적 중 하나는 위에서 보인 eval 및 동일성 함수 안티패턴과 같은 편법을 사용하고 싶은 유혹을 억제하는 것입니다.
요컨대, 다소 임의적인 제한을 제거한다면 그 제한을 모두 제거해야 합니다.
“표현식”의 의미
이 문서 전체에서 “표현식”이라는 단어는 Python 언어 레퍼런스에서 정의된 의미로 사용됩니다. 이는 if, elif, while 블록에서 조건식으로 유효한 모든 것이라고 요약할 수 있습니다. 이는 다소 더 널리 알려진 정의와 미묘하게 다르며, 해당 정의는 eval에 문자열 입력으로 유효한 모든 것이라고 요약할 수 있습니다.
이 “표현식”의 정의는 우리의 요구에 잘 맞고 기존 언어 구성에서 허용되는 문법을 재사용하므로 편리합니다. 이 정의는 다른 정의와 두 가지 미묘한 차이가 있습니다:
튜플 표시식은 반드시 괄호로 묶어야 합니다
이는 Guido가 같은 이메일에서 한 관찰에 근거합니다. 바로 위 내용에서 이어집니다:
하지만 저는 쉼표는 허용하지 않을 것입니다 – 다음과 같은 것이@f, g def pooh(): ...말이 될 방법은 없습니다.
실제로 이는 경험이 부족한 독자로 하여금 마치 데코레이터들이 쌓여 있는 것처럼 여러 개의 데코레이터가 적용되고 있다고 결론짓게 만들 수도 있습니다. 여기서 괄호를 요구하면 추가적인 제약과 문법적 복잡성을 부과하지 않으면서도 (물론 말이 안 되는) 의도를 명확하게 만들어 줍니다.
명명된 표현식은 괄호로 감쌀 필요가 없습니다
여기서는 구문의 선택이 모호하지 않습니다. PEP 572는 최상위 표현식 문에 괄호를 요구하는 이유를 다음과 같이 설명합니다:
이 규칙은 사용자가 대입문과 대입 표현식 사이에서 선택하는 것을 단순화하기 위해 포함되었습니다 – 둘 다 유효한 구문적 위치는 존재하지 않습니다.
여기서는 대입문이 유효하지 않으므로, 대입 표현식에 불필요하게 괄호라는 부담을 지울 필요가 없습니다.
명세
데코레이터에 대한 문법은 현재 다음과 같습니다:
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
이 PEP는 이를 다음과 같이 단순화할 것을 제안합니다:
decorator: '@' namedexpr_test NEWLINE
하위 호환성
이 새로운 문법은 기존 문법과 완전히 하위 호환됩니다.
이를 가르치는 방법
데코레이터는 지금까지 해왔던 방식 그대로 계속 가르칠 수 있습니다. 평범한 파이썬 프로그래머라면 현재의 제약이 존재한다는 사실조차 모를 가능성이 높습니다.
참조 구현
저자는 CPython 구현을 작성했습니다.
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.