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

Python 개선 제안 한국어 번역

PEP 640 – 사용되지 않는 변수 구문

Author:
Thomas Wouters <thomas at python.org>
Status:
Rejected
Type:
Standards Track
Created:
04-Oct-2020
Python-Version:
3.10
Post-History:
19-Oct-2020
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

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

거부 참고

운영 위원회에서 거부됨: https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/

초록

이 PEP는 사용되지 않는 변수를 위한 새로운 구문을 제안하며, 할당할 수는 있지만 그 밖에는 사용할 수 없는 의사 이름을 제공합니다. 할당은 실제로 수행되지 않고, 대신 값이 폐기됩니다.

동기

Python에서는 실제로 결과가 필요하지 않은데도 할당을 수행해야 하는 경우가 어느 정도 흔합니다. 관례적으로 사람들은 "_""unused"와 같은 이름(또는 "unused"를 접두사로 사용하는 이름)을 사용합니다. 이는 언패킹 할당에서 가장 흔합니다.:

x, unused, z = range(3)
x, *unused, z = range(10)

for문과 컴프리헨션에서도 사용됩니다.:

for unused in range(10): ...
[ SpamObject() for unused in range(10) ]

이러한 경우 "_"를 사용하는 것이 아마도 가장 일반적이지만, 국제화에서 "_"를 사용하는 방식과 잠재적으로 충돌합니다. 국제화에서는 gettext.gettext()와 같은 호출을 "_"에 바인딩하고 문자열을 번역 대상으로 표시하는 데 사용합니다.

Python에 패턴 매칭을 추가하자는 제안(원래는 PEP 622였으며, 현재는 PEP 634, PEP 635PEP 636으로 나뉘어 있습니다)에서 "_"추가적인 특별한 의미를 가집니다. 이는 변수를 할당할 수 있는 위치에서 어떤 것이든 매칭하되 아무것에도 할당하지 않아야 함을 나타내는 와일드카드 패턴입니다. 여기서 "_"를 선택한 것은 다른 언어에서 "_"를 사용하는 방식과 일치하지만, Python의 다른 곳에서 사용되는 "_"와의 의미론적 차이는 중요합니다.

이 PEP는 할당에서 유효한 어떤 이름 대신에도 사용할 수 있는 특별한 토큰 "?"를 허용할 것을 제안합니다. 이는 "_"의 대부분의 이점을 유지하면서, 해당 변수를 일반 변수로 사용하는 다른 방식에는 영향을 주지 않습니다. 동일한 와일드카드 패턴을 사용할 수 있도록 하면 패턴 매칭과 언패킹 할당이 서로 더 일관되게 됩니다.

근거

특정 변수를 사용되지 않는 것으로 표시하는 것은 코드의 목적을 명확히 하는 데 도움이 되므로 유용한 도구입니다. 이를 통해 코드 독자와 자동화된 린터 모두 특정 변수가 의도적으로 사용되지 않았음을 명확히 알 수 있습니다.

그러나 이러한 관례에도 불구하고 "_"는 특별한 변수가 아닙니다. 값은 여전히 할당되고, 해당 값이 참조하는 객체는 스코프가 끝날 때까지 계속 살아 있으며, 여전히 사용할 수도 있습니다. 또한 사용되지 않는 변수에 "_"를 사용하는 것이 완전히 보편적인 것도 아닙니다. 관례적인 국제화와 충돌하고, 이것이 일반 변수라는 점이 명확하지 않으며, "unused"라는 이름의 변수만큼 사용되지 않는 변수라는 점이 분명하지 않기 때문입니다.

패턴 매칭 제안에서는 "_"를 와일드카드 패턴에 사용하는 방식이 별도의 스코프에 속한다는 특성 덕분에 사용되지 않는 변수에 "_"를 사용할 때의 문제를 피합니다. 이것이 국제화와 충돌하는 유일한 지점은 혼동 가능성이며, "_"라는 전역 변수의 사용과 실제로 상호 작용하지는 않습니다. 그러나 이 와일드카드 패턴 용도를 위해 "_"를 특별 취급하는 것은 여전히 문제가 됩니다. 패턴 매칭 안팎에서 "_"의 서로 다른 의미론과 의미는 Python의 일관성을 깨뜨립니다.

패턴 매칭 내부와 외부 모두에서 사용되지 않는 변수의 특별한 구문으로 "?"를 도입하면 이러한 일관성을 유지할 수 있습니다. 국제화 또는 _를 변수로 사용하는 다른 용도와의 충돌을 피합니다. 이는 언패킹 할당을 패턴 매칭에 더 가깝게 맞추므로, 패턴 매칭을 언패킹 할당의 확장으로 설명하기가 쉬워집니다.

코드 가독성 측면에서 특별한 토큰을 사용하면 그 의미를 더 쉽게 알아낼 수 있고("what does question mark in Python do""why is my _ variable not getting assigned to"), 값이 사용되지 않아야 한다는 실제 의도도 더 명확해집니다. 이는 해당 값을 사용하는 것이 완전히 불가능하기 때문입니다.

명세

새로운 토큰 "?"또는 token.QMARK이 도입됩니다.

대입 문맥에서 "?"를 허용하도록 문법이 수정됩니다(star_atomt_atom은 현재 문법에 해당함). 이로 인해 식별자가 NULL로 설정된 Name AST 노드가 생성됩니다.

Name표현식의 식별자를 선택 사항으로 허용하도록 AST를 수정합니다(현재는 필수입니다). 식별자가 비어 있는 경우는 STORE 컨텍스트에서만 허용합니다.

CPython에서는 식별자가 없는 Name노드에 대해 바이트코드 컴파일러가 STORE_NAME대신 POP_TOP을 내보내도록 수정됩니다. Name 노드의 다른 사용처도 식별자가 비어 있는 경우를 적절히 처리하도록 업데이트합니다.

수정된 문법 노드의 사용처는 적어도 다음과 같은 대입 형식을 포함합니다:

? = ...
x, ?, z = ...
x, *?, z = ...
for ? in range(3): ...  # including comprehension forms
for x, ?, z in matrix: ...  # including comprehension forms
with open(f) as ?: ...
with func() as (x, ?, z): ...

언패킹 컨텍스트가 아닌 경우 단일 "?"을 일반 대입과 with 문에서 사용할 수 있습니다. 단독으로는 별 의미가 없으며, 이러한 특정 사례를 금지할 수도 있습니다. 그러나 for ? in range(3)은 분명히 활용 사례가 있으므로, 다른 이유가 없더라도 일관성을 위해 다른 경우에도 단일 "?"의 사용을 허용하는 편이 더 합리적으로 보입니다.

"?"는 대입에만 사용할 수 있으므로 확장 대입(? *= 2)에서 "?"를 사용하는 것은 허용되지 않습니다. "?"가 여러 번 나타나는 것은 유효하며, 이름에 대입할 때와 마찬가지로 각 대입은 서로 영향을 주지 않습니다.

하위 호환성

새 토큰을 도입하더라도 하위 호환성 문제는 없습니다. 유효한 구문의 의미는 변경되지 않습니다.

"?"는 식별자로 간주되지 않으므로 str.isidentifier()는 변경되지 않습니다.

그러나 Name 토큰의 식별자가 이제 비어 있을 수 있으므로 AST는 호환되지 않는 방식으로 변경됩니다. AST를 사용하는 코드는 이에 맞게 조정해야 합니다.

이 내용을 가르치는 방법

"?"는 언패킹 대입과 함께 도입할 수 있으며, 이를 ‘사용되지 않음’을 나타내는 특수 구문이라고 설명하고 다른 곳에서도 사용할 수 있음을 언급할 수 있습니다. 또는 for 루프에서 루프 변수가 사용되지 않는 예를 보여 주면서 대입을 설명하는 과정의 일부로 도입할 수도 있습니다.

PEP 636에서는 "_"를 가르치는 방법을 다루며, "_""?"로 단순히 대체하고 "?"도 다른 문맥에서 유사하게 사용할 수 있음을 언급하면 됩니다.

참조 구현

프로토타입 구현이 <https://github.com/Yhg1s/cpython/tree/nonassign>에 존재합니다.

거부된 아이디어

미해결 문제

다음 문맥에서 "?"를 허용해야 합니까?:

# imports done for side-effect only.
import os as ?
from os import path as ?

# Function defined for side-effects only (e.g. decorators)
@register_my_func
def ?(...): ...

# Class defined for side-effects only (e.g. decorators, __init_subclass__)
class ?(...): ...

# Parameters defined for unused positional-only arguments:
def f(a, ?, ?): ...
lambda a, ?, ?: ...

# Unused variables with type annotations:
?: int = f()

# Exception handling:
try: ...
except Exception as ?: ...

# With blocks:
with open(f) as ?: ...

일부는 일관성 측면에서 타당해 보일 수 있지만, 실제 용도는 제한적이고 의문스럽습니다. "?"에 대한 타입 어노테이션과 exceptwith와 함께 사용하는 것은 별 의미가 없어 보입니다. 참조 구현에서는 except가 지원되지 않지만 (기존 구문은 이름만 허용하기 때문입니다), with는 지원됩니다(기존 구문이 언패킹 할당을 지원하기 때문입니다).

패턴 매칭이 거부되더라도 이 PEP를 받아들여야 합니까?