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

Python 개선 제안 한국어 번역

PEP 679 – 괄호를 사용하는 새로운 assert 문 문법

Author:
Pablo Galindo Salgado <pablogsal at python.org>, Stan Ulbrych <stan at python.org>
Discussions-To:
Discourse thread
Status:
Rejected
Type:
Standards Track
Created:
07-Jan-2022
Python-Version:
3.15
Post-History:
08-Sep-2025, 10-Jan-2022
Resolution:
24-Oct-2025

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 assert 키워드의 두 인자 형식에서 괄호를 허용할 것을 제안합니다. 인터프리터는 assert (expr, msg)를 assert expr, msg로 재해석하게 되며, 이를 통해 이전에는 이러한 코드가 항상 참으로 평가되는 두 요소 tuple을 단언하는 것으로 처리되던 흔한 함정을 없앱니다.

동기

오류 메시지를 포함하는 형식의 assert 키워드 문을 사용할 때 이를 괄호로 감싸는 것은 흔한 사용자 실수입니다 [1] [2]. 이는 많은 초보자가 assert 키워드를 함수라고 생각하기 때문입니다. 널리 쓰이는 unittest 메서드들, 특히 assertTrue() 역시 단언과 메시지를 괄호로 감싸야 합니다.

안타깝게도 이 실수는 assert가 항상 통과하기 때문에 발견되지 않고 넘어갑니다 [6]. 표현식이 두 요소 튜플인 assert 문으로 해석되는데, 이 튜플은 항상 참 값을 가지기 때문입니다. 괄호는 검사식이나 설명을 한 줄 너머로 확장하는 자연스러운 방법이기 때문에, 그렇게 할 때에도 이 실수가 자주 발생합니다.

이 실수는 매우 흔해서 3.10부터 컴파일러가 SyntaxWarning을 내보내며, 여러 코드 린터도 경고를 내보냅니다 [3] [4].

또한 언어의 다른 몇몇 문도 어떤 방식으로든 괄호로 감싼 형식을 허용합니다. 예를 들어 import 문(from x import (a,b,c))이나 del 문(del (a,b,c))이 그렇습니다.

괄호를 허용하면 이 함정이 제거될 뿐만 아니라, 사용자와 자동 포매터가 긴 assert 문을 이 문서의 저자들이 더 자연스럽다고 믿는 방식으로 여러 줄에 걸쳐 포매팅할 수 있게 됩니다. 현재도 긴 assert 키워드 문을 백슬래시(PEP 8에서 권장하는 방식)나 괄호와 쉼표를 사용하여 여러 줄에 걸쳐 형식화할 수는 있지만:

assert (
  very very long
  test
), (
  "very very long "
  "error message"
)

이 문서의 저자들은 제안된 괄호 형식이 더 명확하고 직관적이며, 다른 문법 구조의 포매팅과도 더 일관된다고 믿습니다:

assert (
  very very long
  test,

  "very very long "
  "message"
)

근거

하위 호환성에 대한 우려(아래 절 참조)로 인해, 이전에는 두 요소 튜플이던 것이 파싱되는 방식이 새롭게 바뀌었음을 사용자에게 알리기 위해 Python 3.17까지 "new assertion syntax, will assert first element of tuple"과 같은 메시지를 담은 SyntaxWarning이 발생합니다. 예를 들어, 새 문법을 사용하면 다음과 같습니다:

>>> assert ('Petr' == 'Pablo', "That doesn't look right!")
<python-input-0>:0: SyntaxWarning: new assertion syntax, will assert first element of tuple
Traceback (most recent call last):
  File "<python-input-0>", line 1, in <module>
    assert ('Petr' == 'Pablo', "That doesn't look right!")
            ^^^^^^^^^^^^^^^^^
AssertionError: That doesn't look right!

문법 경고 전반을 개선하는 것은 이 PEP의 범위를 벗어난다는 점에 유의하십시오.

명세

assert 키워드 문의 형식 문법은 다음과 같이 변경됩니다 [8]:

| 'assert' '(' expression ',' expression [','] ')' &(NEWLINE | ';')
| 'assert' a=expression [',' expression ]

여기서 첫 번째 줄은 괄호를 허용하는 새로운 형식의 assert 문이며, 3.17까지 SyntaxWarning을 발생시킵니다. 파서가 튜플을 성급하게 전체 문으로 포착하는 것을 막으려면 전방 탐색(lookahead)이 필요하며, 이를 통해 assert (a, b) <= c, "something"과 같은 문도 여전히 올바르게 파싱됩니다.

구현 참고 사항

이 변경은 파서나 컴파일러에서 구현할 수 있습니다. 새 문법을 사용자에게 알리는 SyntaxWarning을 발생시켜야 한다는 명세는 구현을 복잡하게 만드는데, 경고는 컴파일 중에 발생해야 하기 때문입니다.

저자들은 이상적인 구현이 파서에서 이루어지는 것이라고 믿으며 [8], 그 결과 assert (x,y)가 assert x,y와 같은 AST를 갖게 됩니다. 이를 위해서는 불가피한 임시 타협을 포함한 두 단계의 구현 계획이 필요합니다.

파서에서 구현하기

경고 명세가 있는 상태에서는 순수하게 파서만으로 구현하는 것이 불가능합니다. (경고 명세가 없다면 순수 파서 구현은 작은 문법 변경에 불과하다는 점에 유의하십시오 [5].) 경고를 발생시키려면 컴파일러가 새 문법을 인식해야 하며, 이는 선택적 플래그가 필요하다는 것을 의미합니다. 그렇지 않으면 파싱 중에 해당 정보가 손실되기 때문입니다. 따라서 괄호가 있는 assert 키워드 문의 AST는 paren_syntax=1 플래그와 함께 다음과 같은 모습이 됩니다:

>>> print(ast.dump(ast.parse('assert(True, "Error message")'), indent=4))
Module(
    body=[
        Assert(
            test=Constant(value=True),
            msg=Constant(value='Error message'),
            paren_syntax=1)])

컴파일러에서 구현하기

새 문법은 길이가 2인 튜플을 특별히 처리하는 방식으로 컴파일러에서 구현할 수 있습니다. 하지만 이렇게 하면 SyntaxWarning이 발생하는 전환 기간 동안 AST가 전혀 바뀌지 않는 부수 효과가 생깁니다.

SyntaxWarning이 제거되면 구현을 파서 수준으로 옮길 수 있습니다. 그러면 괄호로 묶인 형태가 곧바로 assert expression, message와 같은 AST 구조로 파싱됩니다. AST를 다루는 여러 도구가 적응할 시간을 더 얻으므로 이 방식이 하위 호환성 면에서 더 유리합니다.

하위 호환성

이 변경은 엄밀히 말해 하위 호환되지 않습니다. 처음에 파서에서 구현하든 컴파일러에서 구현하든, assert (x,y)는 assert x,y로 해석됩니다. 현재 이 문은 2-튜플을 대상으로 하는 assert 문으로 해석되어 항상 참으로 평가됩니다.

한편 이런 종류의 assert 문은 항상 통과하므로 사용자 코드에서 사실상 아무 일도 하지 않습니다. 이 문서의 저자들은 이렇게 하위 호환성이 깨지는 것이 오히려 유익하다고 생각합니다. 예전에는 눈에 띄지 않고 넘어갔을 이런 사례가 사용자 코드에서 드러나기 때문입니다. 이 경우는 Python 3.10부터 이미 SyntaxWarning을 발생시켜 왔으므로, 5년이 넘는 폐지 기간이 있었던 셈입니다. SyntaxWarning을 계속 발생시키므로 사용자가 예상치 못한 동작에 당황하는 일이 줄어들 것입니다.

이 변경으로 assert (x,y)의 AST도 바뀝니다. 현재 AST는 다음과 같습니다:

Module(
    body=[
        Assert(
            test=Tuple(
                elts=[
                    Name(id='x', ctx=Load()),
                    Name(id='y', ctx=Load())],
                ctx=Load()))],
    type_ignores=[])

Python 3.18의 최종 구현에서는 다음과 같은 AST가 만들어집니다:

Module(
    body=[
        Assert(
            test=Name(id='x', ctx=Load()),
            msg=Name(id='y', ctx=Load()))],
    type_ignores=[])

문제는 첫 번째 형태의 AST가 엄밀히 말해 “올바르지 않게” 된다는 점입니다. 검사식과 메시지가 있는 assert 문의 AST에는 이미 전용 형태(두 번째 형태)가 있기 때문입니다. 처음에 컴파일러에서 구현하면 이 변경이 늦춰지고 도구들이 적응할 시간을 더 얻으므로 하위 호환성 우려가 줄어듭니다.

교육 방법

assert 문의 새 형태는 언어 표준의 일부로 문서화됩니다.

사용자에게 오류 메시지를 함께 쓰는 assert 문 형태를 가르칠 때, 이제 괄호를 추가해도 예상대로 동작하므로 문을 여러 줄로 나눌 수 있다는 점을 알려 줄 수 있습니다.

참조 구현

파서 쪽 참조 구현은 이 브랜치에서, 컴파일러 쪽 참조 구현은 이 브랜치에서 볼 수 있습니다.

기각된 아이디어

키워드를 사용하는 문법 추가

Python 문법의 다른 모든 곳에서 쉼표는 tuple이나 list의 항목, 함수의 매개변수/인자, 임포트 대상처럼 동질적인 요소로 이루어진 가변 길이 “목록”을 구분합니다. Python 3.0에서 except...as 키워드 구문이 도입된 이후, assert 문은 이 관례에 대한 유일한 예외로 남아 있습니다.

사용자가 혼란을 겪는 이유 중 적어도 일부는 쉼표로 구분된 항목들이 서로 대등하리라는 기대 때문일 수 있습니다. assert 키워드 문의 표현식과 메시지를 괄호로 감싸면 시각적으로 둘을 더욱 강하게 묶게 됩니다. assert를 함수 호출과 더 비슷해 보이게 만들면 잘못된 사고방식을 부추기게 됩니다.

가능한 해결책으로 쉼표를 키워드로 바꾸고 그 형태에서는 괄호를 허용하자는 제안이 있었습니다 [7]. 예를 들면 다음과 같습니다:

assert condition else "message"
assert (condition else "message")

그런 다음 쉼표를 천천히, 신중하게 폐기할 수 있습니다. 괄호 안에 쉼표가 나오는 경우부터 시작하면 되며, 이 경우에는 이미 SyntaxWarning이 발생합니다.

이 PEP의 작성자들은 완전히 새로운 문법을 추가하는 것이 무엇보다도 이 PEP가 패치하고자 하는 흔한 초보자의 함정을 해결하지 못하며, 작성자들이 제안된 문법으로 개선된다고 믿는 여러 줄에 걸친 assert 문의 형식도 개선하지 못할 것이라고 생각합니다.

보안 영향

이 변경에는 보안상 영향이 없습니다.

감사의 글

이 변경은 처음에 python/cpython#90325에서 논의되고 제안되었습니다.

이 PEP의 초안 작성 과정에서 도움을 주신 Petr Viktorin 님께 깊이 감사드립니다.

각주