TECH 으로 돌아가기
TECH HACKER NEWS 6분 읽기 22 READS

None의 모호함을 끝내다: 파이썬 센티널 값과 PEP 661

파이썬에서 None만큼 다양한 의미로 쓰이는 값도 드물다. 무언가가 없다는 뜻으로, 아직 설정되지 않았다는 뜻으로, 오류가 발생했다는 신호로, 때로는 그 자체가 유효한 값으로도 쓰인다. 하나의 값에 이렇게 많은 역할을 몰아넣다 보니, 정작 코드가 '무엇을 표현하려는지' 구분할 수 없게 되는 순간이 찾아온다. 올해 PyConDE/PyData Berlin 2026, EuroPython 2026, 그리고 가장 최근 Swiss Python Summit 2026에서 발표된 센티널 값에 관한 강연은 바로 이 모호함이 왜 문제가 되는지, 그리고 대안이 무엇인지를 짚는다.

None이 무너지는 지점

문제는 의외로 흔한 자리에서 드러난다. 간단한 캐시를 떠올려 보자. 키가 존재하지 않을 때도 None을 반환하고, 키가 실제로 None에 매핑되어 있을 때도 None을 반환한다면, 호출하는 쪽에서는 두 상황을 구분할 방법이 없다. 설정을 갱신하는 코드에서 timeout=None은 '타임아웃 없음'을 뜻하는가, 아니면 '현재 값을 그대로 유지'하라는 뜻인가. 또 TimeoutError를 삼키고 None을 돌려주는 함수는 None을 사실상 오류 신호로 쓰고 있는 셈이다. 세 경우 모두 None이라는 하나의 값에 서로 다른 의미가 겹쳐 있다는 공통점을 가진다.

센티널 값은 이 겹침을 원천적으로 차단한다. 유효한 값들의 영역 바깥에 있는 '경계 표식'을 따로 두는 방식이기 때문에, 실제 데이터와 결코 충돌하지 않는다. '값이 없음'과 '값이 None임'을 명확히 분리할 수 있게 되는 것이다.

파이썬은 이미 센티널을 쓰고 있다

사실 파이썬 자신이 센티널에 깊이 기대고 있다. 눈에 잘 띄지 않을 뿐이다. Ellipsis는 NumPy 슬라이싱에서 차원을 건너뛰는 데 쓰이고, 스텁 코드를 표시하는 용도로도 등장한다. NotImplemented는 '구현을 다른 곳에서 찾으라'는 의미로, __rsub__ 같은 메서드를 통해 이항 연산자의 더블 디스패치를 가능하게 한다. 라이브러리 차원에서도 마찬가지다. Pydantic의 MISSING은 필드가 명시적으로 null로 설정된 경우와 아예 전송되지 않은 경우를 구분해 주는데, 이 기능은 Pydantic 2.14에서 실험 단계를 막 벗어났다. 센티널은 결코 희귀한 기법이 아니라, 성숙한 코드베이스가 이미 널리 채택한 패턴이라는 뜻이다.

직접 만들 때 생기는 함정

문제는 센티널을 직접 만들려 할 때 시작된다. 고전적인 방식인 MISSING = object()는 런타임에서는 완벽하게 동작하지만, 정적 타입 검사기에서 타입 좁히기(type narrowing)가 작동하지 않는다. 이를 우회하려는 여러 기법들, 예컨대 TypeIs 가드나 매직 Literal 문자열, 단일 멤버 Enum 트릭 등은 저마다 트레이드오프를 안고 있다. 게다가 센티널이 복사되거나 pickle로 직렬화·역직렬화되는 과정에서 동일성(identity) 비교가 깨질 수 있다는 점도 현실적인 위험이다. 즉 '정답'처럼 보이는 패턴이 실제 운영 환경에서는 조용히 어긋날 여지가 있었다.

PEP 661, 그리고 3.15의 변화

여기에 반전이 있었다. 센티널을 표준화하려는 제안인 PEP 661은 4월 PyConDE 시점만 해도 보류(deferred) 상태였다. 그런데 불과 9일 뒤, 운영 위원회(Steering Council)가 이를 승인했다. 그 결과 파이썬 3.15부터 sentinel이 내장 기능으로 제공되며, 타입 검사기도 이제 이를 None처럼 자연스럽게 좁혀 처리할 수 있게 되었다. 센티널이 비로소 언어의 일급 시민이 된 셈이다. 구버전 파이썬을 쓰고 있다면 typing_extensions가 백포트를 제공한다. 다만 타입 검사기 쪽 지원은 아직 따라오는 중이므로, 의존하기 전에 자신이 쓰는 검사기가 실제로 이를 지원하는지 확인하는 편이 안전하다.

실무적으로 가져갈 교훈은 분명하다. None이 품고 있는 모호함을 의식하고, 코드가 정말로 표현하려는 바가 무엇인지 먼저 생각하라는 것이다. 모호함을 걷어낼 필요가 있다면 센티널을 쓰되, 가능하면 사용하는 라이브러리가 이미 제공하는 것을 우선 활용하고, 낡은 object()나 Enum 트릭은 새 내장 기능으로 대체하는 것이 좋다. 한 가지 덧붙이자면, 예외를 던지는 대신 None을 반환하고 싶은 유혹이 든다면 그것은 센티널이 아니라 예외 처리나 결과 타입(result type)의 문제일 수 있다. 값의 부재를 어떤 방식으로 표현할지는 결국 코드의 의도를 드러내는 설계의 문제이며, 3.15의 sentinel은 그 의도를 타입 수준에서까지 명확히 적을 수 있는 수단을 비로소 공식적으로 손에 쥐여 준 것이다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://florianwilhelm.info/2026/10/sentinel_values/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...