[Rejected] PEP 640 - Unused variable syntax
원문 링크: PEP 640 - Unused variable syntax
상태: Rejected 유형: Standards Track 작성일: 04-Oct-2020
PEP 640: 사용되지 않는 변수 구문 제안 번역 및 해설
거부(Rejection) 사유
PEP 640은 스티어링 위원회에 의해 거부되었습니다. 관련 내용은 다음 링크에서 확인할 수 있습니다: https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/
초록 (Abstract)
이 PEP는 사용되지 않는 변수를 위한 새로운 구문을 제안합니다. 이 구문은 할당될 수 있지만 다른 목적으로는 사용될 수 없는 가상의 이름을 제공합니다. 실제 할당은 일어나지 않으며, 값은 대신 버려집니다.
동기 (Motivation)
Python에서는 결과가 실제로 필요하지 않음에도 불구하고 할당을 해야 하는 경우가 종종 발생합니다. 일반적으로 이러한 목적으로 _
또는 unused
와 같은 이름(혹은 unused
접두사가 붙은 이름)을 사용합니다. 이는 주로 언패킹(unpacking) 할당에서 가장 흔하게 나타납니다:
x, unused, z = range(3)
x, *unused, z = range(10)
또한, for
루프와 컴프리헨션(comprehension)에서도 사용됩니다:
for unused in range(10):
...
[ SpamObject() for unused in range(10) ]
이러한 경우 _
의 사용이 가장 일반적이지만, 국제화(internationalization)에서 gettext.gettext()
와 같은 호출이 _
에 바인딩되어 번역을 위한 문자열을 표시하는 데 사용될 때 충돌할 수 있습니다.
Python에 패턴 매칭(Pattern Matching)을 추가하기 위한 제안(원래 PEP 622, 현재 PEP 634, PEP 635, PEP 636으로 분할됨)에서는 _
가 추가적인 특별한 의미를 가집니다. 이것은 와일드카드 패턴(wildcard pattern)으로, 변수가 할당될 수 있는 위치에서 어떤 값이든 매칭되지만 아무것도 할당되지 않음을 나타내는 데 사용됩니다. 여기서 _
의 선택은 다른 언어에서 _
를 사용하는 것과 일치하지만, Python의 다른 곳에서 _
의 의미론적 차이는 중요합니다.
이 PEP는 할당에서 유효한 이름 대신 특별한 토큰 ?
를 사용하는 것을 제안합니다. 이것은 _
의 대부분의 이점을 가지면서도, 다른 일반 변수의 사용에 영향을 미치지 않습니다. 동일한 와일드카드 패턴을 허용하면 패턴 매칭과 언패킹 할당이 서로 더 일관성을 갖게 됩니다.
근거 (Rationale)
특정 변수를 사용되지 않음으로 표시하는 것은 코드의 목적을 명확히 하는 데 도움이 되는 유용한 도구입니다. 이는 코드 독자뿐만 아니라 자동화된 린터(linter)에게도 특정 변수가 의도적으로 사용되지 않는다는 것을 명확하게 보여줍니다.
그러나 이러한 관행에도 불구하고 _
는 특별한 변수가 아닙니다. 값은 여전히 할당되고, 참조하는 객체는 스코프(scope) 끝까지 살아있으며, 여전히 사용될 수 있습니다. 또한, _
를 사용되지 않는 변수로 사용하는 것이 완전히 보편적이지는 않습니다. 이는 관습적인 국제화와 충돌하며, 일반 변수라는 것이 명확하지 않고, unused
라는 이름의 변수만큼 명확하게 사용되지 않는다는 것을 보여주지 못합니다.
패턴 매칭 제안에서 와일드카드 패턴을 위한 _
의 사용은 별도의 스코프에 있다는 장점 덕분에 사용되지 않는 변수를 위한 _
의 문제를 비껴갑니다. 국제화와의 유일한 충돌은 잠재적인 혼란일 뿐, 전역 변수 _
의 사용과 실제로 상호작용하지는 않습니다. 그러나 이 와일드카드 패턴 목적을 위한 _
의 특별한 취급은 여전히 문제가 됩니다. 패턴 매칭 내부와 외부에서 _
의 다른 의미론과 의미는 Python의 일관성을 깨뜨립니다.
패턴 매칭 내부와 외부 모두에서 사용되지 않는 변수를 위한 특별한 구문으로 ?
를 도입하면 일관성을 유지할 수 있습니다. 이는 국제화 또는 _
를 변수로 사용하는 다른 모든 경우와의 충돌을 피합니다. 또한 언패킹 할당을 패턴 매칭과 더 밀접하게 일치시켜, 패턴 매칭을 언패킹 할당의 확장으로 설명하기 더 쉽게 만듭니다.
코드 가독성 측면에서, 특별한 토큰을 사용하면 그 의미를 파악하기 더 쉬워집니다 (“Python에서 물음표는 무엇을 하는가” 대 “내 _
변수에는 왜 할당되지 않는가”). 그리고 실제 의도가 값을 사용하지 않는 것임을 더 명확하게 보여줍니다. 왜냐하면 ?
는 사용하는 것이 완전히 불가능하기 때문입니다.
명세 (Specification)
새로운 토큰 ?
또는 token.QMARK
가 도입됩니다.
문법은 할당 컨텍스트(현재 문법에서 star_atom
및 t_atom
)에서 ?
를 허용하도록 수정되며, 식별자가 NULL
로 설정된 Name
AST 노드를 생성합니다.
AST는 Name
표현식의 식별자가 선택 사항이 되도록 수정됩니다(현재는 필수). 식별자가 비어 있는 것은 STORE
컨텍스트에서만 허용됩니다.
CPython에서 바이트코드 컴파일러는 식별자가 없는 Name
노드에 대해 STORE_NAME
대신 POP_TOP
을 방출하도록 수정됩니다. Name
노드의 다른 사용은 식별자가 비어 있는 것을 적절하게 처리하도록 업데이트됩니다.
수정된 문법 노드의 사용은 적어도 다음 형태의 할당을 포함합니다:
? = ...
x, ?, z = ...
x, *?, z = ...
for ? in range(3): ... # 컴프리헨션 형태 포함
for x, ?, z in matrix: ... # 컴프리헨션 형태 포함
with open(f) as ?: ...
with func() as (x, ?, z): ...
언패킹 컨텍스트가 아닌 단일 ?
의 사용은 일반 할당 및 with
문에서 허용됩니다. 이는 그 자체로는 큰 의미가 없으며, 이러한 특정 경우를 금지하는 것도 가능합니다. 그러나 for ? in range(3)
는 분명히 사용처가 있으므로, 다른 이유가 없더라도 일관성을 위해 단일 ?
를 다른 경우에도 허용하는 것이 더 합리적입니다.
증가 할당(? *= 2
)에서 ?
를 사용하는 것은 허용되지 않습니다. ?
는 할당에만 사용될 수 있기 때문입니다. ?
의 여러 발생은 유효하며, 이름을 할당할 때와 마찬가지로 할당이 서로 간섭하지 않습니다.
하위 호환성 (Backwards Compatibility)
새로운 토큰을 도입하는 것은 하위 호환성 문제가 없음을 의미합니다. 유효한 구문의 의미가 변경되지 않습니다.
?
는 식별자로 간주되지 않으므로 str.isidentifier()
의 동작이 변경되지 않습니다.
AST는 호환되지 않는 방식으로 변경됩니다. Name
토큰의 식별자가 이제 비어 있을 수 있기 때문입니다. AST를 사용하는 코드는 이에 따라 조정되어야 합니다.
교육 방법 (How to Teach This)
?
는 언패킹 할당과 함께 소개될 수 있으며, ‘사용되지 않음’을 위한 특별한 구문이며 다른 곳에서도 사용될 수 있음을 설명할 수 있습니다. 또는 for
루프에서의 할당 설명의 일부로 소개될 수 있으며, 루프 변수가 사용되지 않는 예시를 보여줄 수 있습니다.
PEP 636은 _
를 가르치는 방법을 다루고 있으며, 단순히 _
를 ?
로 대체하고, ?
가 다른 컨텍스트에서도 비슷하게 사용될 수 있음을 언급할 수 있습니다.
참조 구현 (Reference Implementation)
프로토타입 구현은 다음에서 확인할 수 있습니다: https://github.com/Yhg1s/cpython/tree/nonassign
거부된 아이디어 (Rejected Ideas)
(내용 없음)
미해결 문제 (Open Issues)
?
가 다음 컨텍스트에서 허용되어야 할까요?
- Side-effect만 있는
import
:import os as ? from os import path as ?
- Side-effect만 있는 함수 정의 (예: 데코레이터):
@register_my_func def ?(...): ...
- Side-effect만 있는 클래스 정의 (예: 데코레이터,
__init_subclass__
):class ?(...): ...
- 사용되지 않는 Positional-only 인수를 위한 매개변수:
def f(a, ?, ?): ... lambda a, ?, ?: ...
- 타입 어노테이션(Type Annotations)이 있는 사용되지 않는 변수:
?: int = f()
- 예외 처리:
try: ... except Exception as ?: ...
with
블록:with open(f) as ?: ...
이들 중 일부는 일관성 측면에서 의미가 있어 보일 수 있지만, 실용적인 사용은 제한적이고 의심스럽습니다. ?
에 대한 타입 어노테이션이나 except
, with
와 함께 사용하는 것은 전혀 의미가 없어 보입니다. 참조 구현에서는 except
가 지원되지 않지만(except
의 기존 구문은 이름만 허용), with
는 지원됩니다(기존 구문이 언패킹 할당을 지원하기 때문).
패턴 매칭이 거부되더라도 이 PEP는 받아들여져야 할까요?
저작권 (Copyright)
이 문서는 퍼블릭 도메인 또는 CC0-1.0-Universal 라이선스 중 더 관대한 조건으로 배포됩니다.
⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.
Comments