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과 항등 함수 안티 패턴 같은 편법을 사용하고 싶은 유혹을 줄이는 것입니다.
요컨대, 다소 자의적인 제한을 없앤다면 모든 제한을 없애야 합니다.
무엇이 “표현식”에 해당하는가
이 문서 전체에서 “표현식”이라는 단어는 파이썬 언어 레퍼런스에 정의된 의미로 사용합니다. 이는 “if, elif, while 블록의 조건식으로 유효한 모든 것”으로 요약할 수 있습니다. 이는 아마도 더 널리 알려진 정의와 미묘하게 다르며, 그 정의는 “eval에 문자열 입력으로 넣었을 때 유효한 모든 것”으로 요약할 수 있습니다.
이러한 “표현식”의 정의는 우리의 요구에 잘 맞고, 기존 언어 구문에서 허용되는 문법을 재사용한다는 점에서 편리합니다. 이 정의는 다른 정의와 두 가지 미묘한 차이가 있습니다:
튜플 디스플레이는 반드시 괄호로 감싸야 합니다
이는 Guido가 같은 이메일에서 밝힌 견해에 근거합니다. 위 내용에서 바로 이어집니다:
다만 쉼표는 허용하지 않겠습니다. 다음과 같은 코드는@f, g def pooh(): ...결코 말이 될 수 없기 때문입니다.
오히려 경험이 부족한 독자는 데코레이터 여러 개가 쌓여 있는 것처럼 여러 데코레이터가 적용된다고 오해할 수도 있습니다. 여기서 괄호를 요구하면 추가적인 제약이나 문법상의 복잡함을 더하지 않고도 (분명 말이 안 되는 코드이기는 하지만) 그 의도를 명확히 드러낼 수 있습니다.
명명된 표현식은 괄호로 감쌀 필요가 없습니다
여기서는 문법 선택에 모호함이 없습니다. PEP 572는 최상위 표현식 문장을 괄호로 감싸도록 요구하는 이유를 다음과 같이 설명합니다:
이 규칙은 사용자가 대입문과 대입 표현식 중 하나를 더 쉽게 고를 수 있도록 하기 위해 포함되었습니다 – 둘 다 유효한 구문 위치는 존재하지 않습니다.
이 위치에서는 대입문이 유효하지 않으므로, 대입 표현식에 불필요하게 괄호라는 부담을 지워서는 안 됩니다.
명세
현재 데코레이터의 문법은 다음과 같습니다:
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
이 PEP는 이를 다음과 같이 단순화할 것을 제안합니다:
decorator: '@' namedexpr_test NEWLINE
하위 호환성
이 새로운 문법은 기존 문법과 완전히 하위 호환됩니다.
교육 방법
데코레이터는 지금까지와 같은 방식으로 계속 가르치면 됩니다. 일반적인 Python 프로그래머는 현재 이런 제약이 있다는 사실조차 모를 가능성이 높습니다.
참조 구현
저자가 CPython 구현을 작성했습니다.
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.