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

Python 개선 제안 한국어 번역

PEP 531 – 존재 확인 연산자

Author:
Alyssa Coghlan <ncoghlan at gmail.com>
Status:
Withdrawn
Type:
Standards Track
Created:
25-Oct-2016
Python-Version:
3.7
Post-History:
28-Oct-2016

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 PEP 505 및 관련 논의에서 영감을 받아 Python에 두 가지 새로운 제어 흐름 연산자를 추가할 것을 제안합니다:

  • 존재 확인 전제 조건(“exists-then”): expr1 ?then expr2
  • 존재 확인 대체값(“exists-else”): expr1 ?else expr2

또한 일반적인 존재 확인 식과 문을 위한 다음과 같은 약어도 제안합니다:

  • 존재 확인 속성 접근: obj?.attr (obj ?then obj.attr의 경우)
  • 존재 확인 첨자 사용: obj?[expr] (obj ?then obj[expr]의 경우)
  • 존재 확인 대입: value ?= expr (value = value ?else expr의 경우)

이러한 새로운 연산자 정의에서 공통으로 사용되는 ? 기호는 if 문, while 루프, 컴프리헨션, 제너레이터 식, 조건식, 논리곱 및 논리합에서 사용하는 기존의 진위 확인 프로토콜이 아니라 새로운 “존재 확인” 프로토콜을 사용한다는 것을 나타냅니다.

이 새로운 프로토콜은 operator.exists로 제공되며, 다음과 같은 특징을 가집니다:

  • 타입은 새로운 __exists__ 매직 메서드(Python) 또는 tp_exists 슬롯(C)을 정의하여 기본 동작을 재정의할 수 있습니다. 이 선택적 메서드는 __bool__와 동일한 시그니처 및 가능한 반환값을 가집니다.
  • operator.exists(None)False를 반환합니다.
  • operator.exists(NotImplemented)False를 반환합니다.
  • operator.exists(Ellipsis)False를 반환합니다.
  • float, complexdecimal.Decimal은 존재 확인을 재정의하여 NaN 값은 False를 반환하고, 다른 값(0 값 포함)은 True를 반환하도록 합니다.
  • 그 밖의 모든 타입에서는 operator.exists(obj)가 기본적으로 True를 반환합니다. 가장 중요한 점은 진위 확인 컨텍스트에서 False로 평가되는 값(0, 빈 컨테이너)도 존재 확인 컨텍스트에서는 여전히 True로 평가된다는 것입니다.

PEP 철회

이 PEP를 python-ideas에서 논의하도록 게시할 때 [4]의 검토자들에게 이 특정 구문 제안의 세부 사항을 검토하기 전에 세 가지 고수준 설계 질문을 고려해 달라고 요청했습니다:

1. 우리는 “존재 확인”이 소프트웨어 개발에 존재하는 유용한 일반 개념이며 “진위 확인” 개념과 구별된다는 데 모두 동의합니까? 우리는 “존재 확인”이 소프트웨어 개발에 존재하는 유용한 일반 개념이며 “진위 확인” 개념과 구별된다는 데 모두 동의합니까? 2. 우리는 Python 생태계가 다음과 같은 존재 확인 프로토콜의 혜택을 받을 것이라는 데 모두 동의합니까? 언어 정의, 표준 라이브러리 및 사용자 지정 코드에서 정의된 것을 포함하여 서로 다른 “데이터 누락” 표시자에 걸쳐 알고리즘(특히 단락 평가를 사용하는 알고리즘)을 일반화할 수 있는 존재 확인 프로토콜의 혜택을 받을 것이라는 데 모두 동의합니까? 3. 우리는 다음과 같은 것을 사용하기가 더 쉬워질 것이라는 데 모두 동의합니까? 진위 확인용 “and” 및 “or” 제어 흐름 연산자에 대응하는 존재 확인 연산자를 사용할 수 있다면 이러한 프로토콜을 효과적으로 사용하기가 더 쉬워질 것이라는 데 모두 동의합니까?

첫 번째 질문에 대한 답변은 대체로 긍정적이었지만, 두 번째 질문에 대한 답변은 “아니요”라는 것이 곧 분명해졌습니다.

Steven D’Aprano는 [5]에서 반론을 잘 설명했지만, 일반적인 요지는 “누락된 데이터” 센티널을 확인할 때 거의 항상 특정 센티널 값을 찾는다는 것이며, 어떤 센티널 값이든 찾는 것은 아니라는 것입니다.

예를 들어 NotImplemented가 존재하는 이유는 None이 오버로드된 산술 연산자에서 잠재적으로 정당한 결과일 수 있고, 예외 처리는 피연산자 강제 변환에 사용하기에는 런타임 오버헤드가 너무 크기 때문입니다.

마찬가지로 Ellipsis가 존재하는 이유는 다차원 슬라이싱을 지원하기 위해서이며, 슬라이싱 컨텍스트에서 None이 이미 다른 의미(기본 시작 또는 중지 인덱스, 혹은 기본 단계 크기의 사용을 나타냄)를 가지고 있기 때문입니다.

수학에서 NaN의 가치는 programmatically로는 해당 타입의 일반 값처럼 동작하면서(예: 모든 일반 속성과 메서드를 제공함), 산술적으로는 NaN 값을 처리하는 수학적 규칙에 따라 동작한다는 데 있습니다.

핵심 설계 개념이 무효화되었으므로 제안 전체가 타당하지 않으며, 이에 따라 철회합니다.

그러나 이 제안에 대한 논의는 새로운 구문을 도입하지 않고 기존 and, orif-else 연산자를 더 유연하게 만드는 잠재적인 프로토콜 기반 접근법을 검토하게 했으므로 [6], 이를 PEP 505의 또 다른 가능한 대안으로 작성할 예정입니다.

다른 PEP와의 관계

이 PEP는 Mark Haase가 PEP 505를 작성하면서 수행한 훌륭한 작업에서 영감을 받았고 이를 기반으로 하지만, 제안된 기능의 구체적인 구문과 의미론에서 상당한 차이가 있으므로 궁극적으로 해당 PEP와 경쟁합니다.

또한 전형적인 애플리케이션 및 서비스 개발 활동의 요구 사항이 실제로 변화하고 있다는 점을 고려하여 기존 Python 사용자에게 제공되는 이점에 초점을 맞춤으로써 이러한 변경의 근거에 대해 다른 관점을 제시합니다. 여러 프로그래밍 언어에서 이제 유사한 기능이 등장하는 것은 우연이 아니며, 다른 언어 설계자들이 이 문제를 다루는 방식을 참고하는 것은 좋은 방법이지만, 다른 곳에서 마련된 선례는 애초에 우리가 해결해야 할 문제라고 생각하는지 여부보다는 이 문제를 어떻게 해결할 것인지와 더 관련이 있습니다.

근거

존재 확인 표현

현대 소프트웨어 개발에서 점점 더 일반적인 요구 사항은 “반구조화된 데이터”를 다루는 것입니다. 즉, 데이터의 구조는 사전에 알려져 있지만 런타임에 그 일부가 누락될 수 있으며, 해당 데이터를 조작하는 소프트웨어는 완전히 실패하기보다는 정상적으로 성능을 저하하도록(예: 누락된 데이터에 의존하는 결과를 생략하는 방식으로) 기대됩니다.

이 문제가 발생하는 특히 일반적인 경우는 다음과 같습니다.

  • 선택적인 애플리케이션 구성 설정 및 함수 매개변수 처리
  • 분산 시스템에서 외부 서비스 실패 처리
  • 일부 불완전한 레코드를 포함하는 데이터 세트 처리

이 PEP의 주된 동기는 후자의 두 경우입니다. 선택적인 구성 설정 및 매개변수를 처리해야 한다는 것은 Python 자체만큼이나 오래된 설계 요구 사항이지만, 공용 클라우드 인프라의 부상, 분산 서비스의 협업 네트워크로서 소프트웨어 시스템을 개발하는 방식, 그리고 분석을 위한 대규모 공용 및 사설 데이터 세트의 가용성으로 인해 부분적인 서비스 실패나 부분적인 데이터 가용성에 직면했을 때 작업을 정상적으로 저하할 수 있는 능력이 현대 프로그래밍 환경의 필수 기능이 되고 있습니다.

현재 Python으로 이러한 소프트웨어를 작성하는 일은 실제로 상당히 까다로울 수 있습니다. 코드가 다음과 같은 표현으로 가득 차게 되기 때문입니다.

  • value1 = expr1.field.of.interest if expr1 is not None else None
  • value2 = expr2["field"]["of"]["interest"] if expr2 is not None else None
  • value3 = expr3 if expr3 is not None else expr4 if expr4 is not None else expr5

이러한 표현이 가끔만 나타난다면 전체 문장 형식으로 확장하는 것이 가독성을 개선하는 데 도움이 될 수 있지만, 이러한 표현이 연속해서 4~5개 나타난다면(데이터 변환 파이프라인에서 상당히 흔한 상황입니다) 이를 16~20줄의 조건부 로직으로 대체해도 상황 개선에 거의 도움이 되지 않습니다.

위의 세 예제를 이러한 방식으로 확장하면 다음 점을 설명하는 데 도움이 될 것입니다.:

if expr1 is not None:
    value1 = expr1.field.of.interest
else:
    value1 = None
if expr2 is not None:
    value2 = expr2["field"]["of"]["interest"]
else:
    value2 = None
if expr3 is not None:
    value3 = expr3
else:
    if expr4 is not None:
        value3 = expr4
    else:
        value3 = expr5

이 PEP의 제안들이 결합되어 얻는 효과는 위의 예제 표현을 대신 다음과 같이 작성할 수 있게 하는 것입니다.

  • value1 = expr1?.field.of.interest
  • value2 = expr2?["field"]["of"]["interest"]
  • value3 = expr3 ?else expr4 ?else expr5

이러한 형식에서는 독자에게 제시되는 정보의 거의 대부분이 “이 코드는 무엇을 합니까?”라는 질문과 즉시 관련되는 반면, 누락된 데이터를 출력으로 전달하여 처리하거나 대체 입력으로 대체하는 상용구 코드는 ? 기호를 두 번 사용하고 ?else 키워드를 두 번 사용하는 수준으로 줄어듭니다.

처음 두 예제에서는 31자 길이의 상용구 절 if exprN is not None else None(한 글자 변수 이름을 사용할 때 최소 27자)이 단일 ? 문자로 대체되어 행의 신호 대 패턴 잡음 비율이 크게 향상됩니다(특히 표현을 짧게 보이게 하려는 이유만으로 변수와 필드 이름을 줄이는 대신 더 의미 있는 변수 및 필드 이름을 사용하도록 유도하는 경우에 그렇습니다).

마지막 예제에서는 21자 길이의 상용구인 if exprN is not None(최소 17자)이 두 번 나타나던 것이 단일 문자로 대체되어, 여기서도 신호 대 패턴 잡음 비율이 크게 향상됩니다.

또한 “잠재적으로 관심 있는 하위 표현” 5개가 각각 정확히 한 번씩 포함되므로, 존재 여부를 먼저 확인하기 위해 그중 4개를 복제하거나 이름이 지정된 변수로 분리할 필요가 없습니다.

존재 확인 전제 조건 연산자는 주로 존재 확인 속성 접근 연산자와 첨자 표기 연산자를 위한 명확한 개념적 기반을 제공하도록 정의됩니다.

  • obj?.attr는 대략 obj ?then obj.attr와 같습니다.
  • obj?[expr]는 대략 obj ?then obj[expr]와 같습니다.

축약 형식과 확장된 동등 형식의 주요 의미론적 차이는 존재 확인 연산자의 왼쪽에 있는 공통 하위 표현이 축약 형식에서는 한 번만 평가된다는 점입니다(증강 할당 문이 제공하는 이점과 유사합니다).

존재 확인 대입

존재 확인 대입은 이 PEP의 개념을 확장하여 다음과 같은 일반적인 구성 처리 관용구도 다루기 위한 비교적 간단한 방법으로 제안됩니다.

  • value = value if value is not None else expensive_default()

이를 다음과 같이 줄여 쓸 수 있도록 하는 것입니다.

  • value ?= expensive_default()

이는 대상이 첨자 연산 또는 하위 속성일 때 주로 유용합니다. 이처럼 구체적인 변경이 없더라도 PEP에서는 이 관용구를 다음과 같이 변경하는 것을 여전히 허용하기 때문입니다.

  • value = value ?else expensive_default()

이 형식을 추가하는 것에 대한 주요 반대 주장은 이것이 모호할 수 있으며 다음 중 어느 쪽을 의미할 수도 있다는 점입니다.

  • value = value ?else expensive_default(); 또는
  • value = value ?then value.subfield.of.interest

두 번째 형식은 전혀 유용하지 않지만, 이 우려가 증강 대입 기능을 유지하면서도 해결해야 할 만큼 중요하다고 판단된다면 전체 키워드를 구문에 포함할 수 있습니다.

  • value ?else= expensive_default()

또는 현재 제안에서 증강 대입을 완전히 제외하고 나중에 재검토할 수도 있습니다.

존재 확인 프로토콜

존재 확인 프로토콜은 주로 프록시 객체(예: 원격 리소스를 로컬에서 표현하는 객체)와 테스트에 사용되는 모의 객체가 프록시 또는 모의 객체 자체는 None이 아니더라도 대상 리소스가 존재하지 않음을 올바르게 나타낼 수 있도록 하기 위해 이 제안에 포함됩니다.

그러나 이 프로토콜이 정의되면 숫자형에서 NaN 값을 확인하는 타입 독립적인 방법을 제공하도록 확장하는 것도 자연스러워 보입니다. - 현재는 작업 중인 정확한 데이터 형식을 알고 있어야 합니다. (예: 내장 부동 소수점 수, 내장 복소수, decimal 모듈) 그리고 적절한 연산(예: 각각 math.isnan, cmath.isnan, decimal.getcontext().is_nan())을 사용해야 합니다.

마찬가지로 다른 자리 표시자 내장 싱글턴인 EllipsisNotImplemented도 데이터를 나타낸다기보다는 데이터의 부재를 나타내는 객체에 해당한다고 선언하는 것이 합리적으로 보입니다.

제안된 기호 표기법

Python에는 역사적으로 암시적인 불리언 컨텍스트가 한 가지뿐이었습니다. 바로 bool()내장 함수로 직접 호출할 수 있는 참 검사입니다. 이 PEP에서는 참 검사가 아닌 존재 확인에 기반한 새로운 종류의 제어 흐름 연산을 제안하므로, 참 검사가 아닌 존재 확인이 사용되는 경우 이를 코드에서 직접 상기시킬 수 있도록 하는 것이 유용하다고 봅니다.

존재 명제의 수학 기호는 U+2203 ‘THERE EXISTS’입니다:

따라서 이 PEP에서 제안하는 구문 추가에 대한 한 가지 가능한 접근법은 이미 정의된 해당 수학 표기법을 사용하는 것입니다.

  • expr1 ∃then expr2
  • expr1 ∃else expr2
  • obj∃.attr
  • obj∃[expr]
  • target ∃= expr

그러나 이 접근법에는 실용적인 문제와 교육적인 문제라는 두 가지 주요 문제가 있습니다.

실용적인 문제는 대부분의 키보드가 기본 산술에 사용되는 기호 이외의 수학 기호를 쉽게 입력할 방법을 제공하지 않는다는 일반적인 문제입니다(이 PEP에 나타나는 기호조차도 결국 직접 입력한 것이 아니라 [3]에서 복사하여 붙여 넣은 것입니다).

교육적인 문제는 존재 명제()와 전칭 명제()의 기호가 기본 산술 연산자만큼 대부분의 사람에게 익숙하지 않다는 점입니다. 따라서 를 채택한다고 해서 제안된 구문을 실제로 더 쉽게 이해할 수 있게 되는 것은 아닙니다.

이와 대조적으로, ?는 Python 구문에서 아직 사용되지 않은 몇 안 되는 ASCII 문장 부호 문자 중 하나이므로, “이 제어 흐름 연산은 참 검사(truth check)가 아니라 존재 확인에 기반합니다”를 나타내는 구문 표지 후보로 사용할 수 있습니다.

이 경로를 택하면 유사한 기능을 제공하는 다른 언어의 대응 구문에 Python의 구문을 맞출 수 있다는 장점도 있습니다.

관련 PEP 505의 기존 요약과 “안전 탐색 연산자 [1] 및 “널 병합 연산자” [2]에 관한 위키백과 문서를 바탕으로 살펴보면 다음과 같습니다:

  • ?. 존재 확인 속성 접근 구문은 다음과 정확히 대응합니다.
    • C#의 “안전 탐색” 속성 접근 연산자 (?.)
    • Swift의 “선택적 체이닝” 연산자 (?.)
    • Groovy의 “안전 탐색” 속성 접근 연산자 (?.)
    • Dart의 “조건부 멤버 접근” 연산자 (?.)
  • ?[] 존재 확인 속성 접근 구문은 다음과 정확히 대응합니다.
    • C#의 “안전 탐색” 첨자 연산자 (?[])
    • Swift의 “선택적 첨자” 연산자 (?[].)
  • ?else 존재 확인 대체 구문은 의미상 다음과 대응합니다.
    • C#의 “널 병합” 연산자 (??)
    • PHP의 “널 병합” 연산자 (??)
    • Swift의 “nil 병합” 연산자 (??)

분명히 하자면, 다른 언어에서 사용되는 이러한 연산자의 표기가 이것들뿐인 것은 아니지만 가장 일반적인 표기이며, ? 기호는 단연 가장 일반적인 구문 표지입니다. 이는 아마도 여러 언어가 제공하는 C 스타일 조건식에서 “then” 절을 도입하는 데 ?를 사용하는 관례에서 비롯된 것으로 보입니다.

제안된 키워드

기호 표지 ?가 주어지면, 존재 확인 전제 연산과 대체 연산을 참 검사 대응 연산에서 사용하는 것과 동일한 키워드로 표기해도 구문적으로 모호하지 않습니다.

  • expr1 ?and expr2 (expr1 ?then expr2 대신)
  • expr1 ?or expr2 (expr1 ?else expr2 대신)

그러나 이 접근 방식은 작성할 때는 구문적으로 모호하지 않지만 코드를 발음하기가 엄청나게 어렵고(“?”는 어떻게 발음합니까?) 설명하기도 어렵습니다. 재사용된 키워드 때문에 “존재 확인 전제(?and)”와 “존재 확인 대체(?or)”를 “논리곱(and)” 및 “논리합(or)”과 구별할 수 있는 명확한 약칭이 없기 때문입니다.

? 기호를 “exists”라고 발음하도록 사람들을 유도하여 약칭을 “exists-and 표현식”과 “exists-or 표현식”으로 정할 수도 있지만, 코드 조각에서 해당 표현식을 글로 보는 것만으로는 그 이름을 추측할 방법이 없습니다.

대신 이 PEP는 제안된 기호 구문을 활용하여 새 키워드(?then)를 도입하고 기존 키워드(?else)를 차용합니다. 이를 통해 사람들이 모호함 없이 “then 표현식”과 “else 표현식”을 지칭할 수 있습니다.

이러한 키워드는 제안된 표현식과 의미상 동등한 조건식과도 잘 대응합니다.

?else 표현식의 경우, expr1 ?else expr2는 다음과 동등합니다.:

_lhs_result = expr1
_lhs_result if operator.exists(_lhs_result) else expr2

축약형과 확장형 모두 끝에 else expr2가 나타나므로 여기서 대응 관계는 분명합니다.

?then 표현식의 경우, expr1 ?then expr2는 다음과 동등합니다.:

_lhs_result = expr1
expr2 if operator.exists(_lhs_result) else _lhs_result

Python의 전통적으로 이름이 없는 “then” 절(if 문에서는 :로 도입되고 조건식에서는 if가 뒤에 붙음) 때문에 여기서 대응 관계가 즉시 명확하지는 않지만, 제어 흐름에 대한 “if-then-else” 설명에 이미 익숙하다면 여전히 상당히 명확합니다.

위험과 우려 사항

가독성

새로운 구문을 효과적으로 읽고 쓰는 방법을 배우려면 주로 다음 두 가지 개념을 내면화해야 합니다.

  • ?를 포함하는 표현식은 존재 확인을 포함하며 단락 평가를 수행할 수 있습니다.
  • None 또는 다른 “존재하지 않는” 값이 예상 입력이고, 이를 결과로 전달하는 것이 올바른 처리라면, 존재 확인 연산자가 아마도 원하는 것일 가능성이 큽니다.

현재 이러한 개념은 언어 수준에서 명시적으로 표현되지 않으므로, 조건식과 조건문을 기반으로 하는 다양한 관용적 패턴을 인식하고 사용하는 방법을 익혀야 합니다.

마법 구문

구문 요소인 ?에는 본질적으로 is not None 또는 operator.exists를 암시하는 것이 없습니다. 현재 Python 코드에서 기호로서 ?의 주요 용도는 IPython 환경에서 뒤따르는 접미사로 사용하여 앞선 표현식의 결과에 대한 도움말 정보를 요청하는 것입니다.

그러나 존재 확인이라는 개념은 진리값 확인과 구별되는, 널리 사용되는 시각적 표식의 이점을 실제로 누리며, 이를 도입한다면 한 문자로 된 기호 구문이 필요합니다.

개념적 복잡성

이 제안은 현재 임의적이고 비공식적인 “존재 확인” 개념을 명확하게 정의된 연산자 프로토콜을 갖춘 구문적 언어 기능의 지위로 끌어올립니다.

여러 측면에서 이는 언어의 전반적인 개념적 복잡성을 실제로 줄일 수 있습니다. bool(expr)를 사용한 진리값 확인과 operator.exists(expr)를 사용한 존재 확인 사이에서는 현재 expr is not None을 사용한 진리값 확인과 존재 확인 사이에서 대응하는 것보다 훨씬 더 많은 기대가 올바르게 대응하기 때문입니다(피연산자 강제 변환의 맥락에서 expr is not NotImplemented이거나, 수학 라이브러리의 다양한 NaN 확인 연산인 경우와 비교할 수 있습니다).

이 PEP가 도입하는 새로운 유사성의 간단한 예로 다음을 비교해 보십시오.:

all_are_true = all(map(bool, iterable))
at_least_one_is_true = any(map(bool, iterable))
all_exist = all(map(operator.exists, iterable))
at_least_one_exists = any(map(operator.exists, iterable))

설계 논의

존재 확인 표현식 연결의 미묘한 점

논리 연산자를 연결할 때와 마찬가지로 존재 확인 표현식을 연결할 때도 유사한 미묘한 점이 발생합니다. 연결된 표현식 중 하나의 우변 자체가 존재하지 않는 값을 반환하면 동작이 예상과 다를 수 있습니다.

그 결과, value = arg1 ?then f(arg1) ?else default()은 본질적으로 value = cond and expr1 or expr2이 의심스러운 것과 같은 이유로 의심스럽습니다. 전자는 f(arg1)None을 반환하면 default()를 평가하고, 후자는 불리언 맥락에서 expr1False로 평가되면 expr2를 평가하기 때문입니다.

조건식과의 모호한 상호작용

현재 작성된 제안에서는 다음이 구문 오류입니다.

  • value = f(arg) if arg ?else default

반면 다음은 첫 번째 조건이 단순히 거짓인 경우가 아니라 존재하지 않을 때 두 번째 조건을 확인하는 유효한 연산입니다.

  • value = expr1 if cond1 ?else cond2 else expr2

앞서 설명한 표현식 연결 문제를 고려하면, 첫 번째 연산은 대신 다음과 동등해야 한다고 주장할 수 있습니다.

  • value = f(arg) if operator.exists(arg) else default

따라서 두 번째 연산은 아마도 더 명확한 다음 형식으로 작성해야 합니다.

  • value = expr1 if (cond1 ?else cond2) else expr2

또는 첫 번째 형식을 구문 오류로 유지하고, 존재 확인 기호를 대신 if 키워드에 붙일 수도 있습니다.

  • value = expr1 if? cond else expr2

다른 진리값 확인 맥락에서의 존재 확인

현재 진리값 확인 프로토콜은 다음 구문 구성에서 사용됩니다.

  • 논리적 결합(and 표현식)
  • 논리적 분리(or 표현식)
  • 조건 표현식(if-else 표현식)
  • if 문
  • while 루프
  • 컴프리헨션과 제너레이터 표현식의 필터 절

현재 PEP에서, andor를 사용한 참 여부 검사에서 존재 여부 검사로 전환하는 것은 적절한 위치에 새로운 키워드인 ?then?else를 대입하는 문제입니다.

그 밖의 참 여부 검사 컨텍스트에 대해서는, operator.exists API를 임포트하여 사용하거나, 아니면 expr is not None(또는 컨텍스트에 맞는 동등한 표현)을 구체적으로 검사하는 현재의 관용구를 계속 사용할 것을 제안합니다.

이와 관련하여 가장 단순하게 가능한 개선은 제안된 exists() API를 operator 모듈 함수에서 새로운 내장 함수로 격상시키는 것입니다.

대안으로, ? 존재 여부 검사 기호를 ifwhile 키워드의 수식자로 지원하여 참 여부 검사가 아닌 존재 여부 검사의 사용을 나타내도록 할 수 있습니다.

하지만 두 제안 중 어느 쪽이든 얻을 수 있는 잠재적 일관성 이점이 추가적인 혼란을 정당화할 만큼인지는 전혀 명확하지 않으므로, 현재 이들은 제안에서 제외되어 있습니다.

__bool____exists__간의 예상되는 불변 관계 정의

이 PEP는 현재 기존의 모든 타입에서 __bool__의 정의를 수정하지 않은 채로 두고 있으며, 이는 전체 제안이 하위 호환성을 유지하도록 보장하지만, 그 결과 bool(obj)True를 반환하는데도 제안된 operator.exists(obj)False를 반환하는 다음과 같은 경우들이 발생합니다:

  • float, complex, decimal.DecimalNaN
  • Ellipsis
  • NotImplemented

이를 잠재적으로 변경해야 한다는 주된 논거는, 존재 여부 검사 맥락에서 자신이 존재하지 않음을 나타내는 값들은 참 여부 검사 맥락에서도 스스로를 False로 보고해야 한다는 권장 불변 규칙을 마련해두면 잠재적인 코드 동작을 추론하기가 더 쉬워진다는 것입니다.

이러한 불변 규칙을 정의하지 않으면, float("NaN") ?else 0.00.0을 반환하는 반면 float("NaN") or 0.0NaN을 반환하는 것과 같이 다소 이상하다고 할 수 있는 결과로 이어질 수 있습니다.

한계

임의의 센티널 객체

이 제안은 “센티널 객체” 관용구, 즉 None이 명시적으로 허용되는 값이어서 누락된 값을 나타내기 위해 별도의 센티널 객체가 정의되는 관용구에 대한 구문적 지원을 제공하려 시도하지 않습니다.:

_SENTINEL = object()
def f(obj=_SENTINEL):
    return obj if obj is not _SENTINEL else default_value()

이는 존재 프로토콜 정의를, 정의하고 사용하는 양쪽 모두에서 상당히 더 복잡하게 만드는 대가를 치르면 잠재적으로 지원될 수 있습니다:

  • Python 계층에서 operator.exists__exists__ 구현은 존재하지 않음을 나타내기 위해 빈 튜플을 반환하고, 그렇지 않으면 존재 여부 검사의 결과로 사용될 객체에 대한 참조를 담은 단일 요소 튜플을 반환합니다.
  • C 계층에서 tp_exists 구현은 존재하지 않음을 나타내기 위해 NULL을 반환하고, 그렇지 않으면 존재 여부 검사의 결과로 PyObject * 포인터를 반환합니다.

이러한 변경이 주어지면, sentinel 객체 관용구는 다음과 같이 다시 작성될 수 있습니다::

class Maybe:
  SENTINEL = object()
  def __init__(self, value):
      self._result = (value,) is value is not self.SENTINEL else ()
  def __exists__(self):
      return self._result

def f(obj=Maybe.SENTINEL):
    return Maybe(obj) ?else default_value()

하지만 저는 제안된 3가지 표준 sentinel 값(즉, None, Ellipsis, NotImplemented)을 사용할 수 없는 경우가, 추가적인 프로토콜 복잡성과 __bool____exists__ 사이의 대칭성 상실을 감수할 만큼 충분히 흔하지는 않을 것이라고 생각합니다.

명세

초록(Abstract)은 이미 제안의 요지를 제시하며, 근거(Rationale)는 몇 가지 구체적인 예시를 제공합니다. 기본 아이디어에 대한 관심이 충분하다면, 완전한 명세는 참조 구현의 작성을 안내하기에 충분할 만큼, 제안된 문법적 설탕(syntactic sugar)과 그 기저의 조건식 사이의 정확한 대응 관계를 제공해야 할 것입니다.

…TBD…

구현

실제 구현은 PEP 505에서와 마찬가지로, 이 연산자들을 추가하는 아이디어에 대한 원칙적인 관심이 확인될 때까지 보류되어 왔습니다 — 이 제안들에서 어려운 부분은 구현이 아니라, 신규 및 기존 파이썬 사용자에게 돌아가는 장기적 이익이 (다른 구현체의 개발자, 언어 커리큘럼 개발자, 그 밖의 파이썬 관련 교육 자료 저자를 포함한) 더 넓은 생태계가 이 변경에 적응하는 데 드는 단기적 비용을 능가하는 변경인지 여부를 판단하는 것입니다.

…TBD…

참고 문헌