본문으로 건너뛰기

[cpython] CPython 최적화: functools.reduce 대신 Union 직접 사용하기

PR 링크: python/cpython#155280 상태: Merged | 변경: +3 / -2

들어가며

Python의 typing 모듈에서 Union 타입을 다룰 때, 기존에는 여러 타입을 하나로 합치기 위해 functools.reduce(operator.or_, args) 방식을 사용해 왔습니다. 하지만 이 방식은 타입 개수가 늘어날수록 연산 비용이 기하급수적으로 증가하는 문제가 있었습니다. CPython의 이번 PR(gh-105499)은 Union 객체를 재구성할 때 functools.reduce를 제거하고, Union[args] 문법을 직접 사용하여 성능을 대폭 개선했습니다.

코드 분석

Lib/typing.py

핵심 변경 사항은 _eval_type 함수와 _strip_annotations 함수 내에서 functools.reduce를 제거하고 Union 인덱싱을 사용하는 것입니다.

Before:

if isinstance(t, Union):
    return functools.reduce(operator.or_, ev_args)

After:

if isinstance(t, Union):
    return Union[ev_args]

이 변경은 reduce를 통해 매번 | 연산자를 호출하며 새로운 Union 객체를 생성하는 오버헤드를 줄이고, Union 생성자가 내부적으로 최적화된 방식으로 인자들을 처리하게 함으로써 성능 이득을 얻습니다.

Lib/test/test_typing.py

변경 사항의 정확성을 검증하기 위해 테스트 코드에도 Union[args]를 사용하는 케이스가 추가되었습니다.

After:

self.assertEqual(expr1, reduce(operator.or_, args))
self.assertEqual(expr1, Union[args])

왜 이게 좋은가

성능 향상

벤치마크 결과에 따르면, 타입 멤버가 80개인 경우 reduce 방식 대비 약 35.66배의 속도 향상을 보였습니다. 타입 개수가 적을 때는 차이가 미미하지만, 복잡한 타입 힌트가 많은 대규모 코드베이스에서는 typing 모듈의 오버헤드를 획기적으로 줄일 수 있습니다.

교훈

  1. 내장 문법 활용: 특정 기능을 구현할 때 범용 라이브러리(functools.reduce)를 사용하는 것보다, 언어 차원에서 제공하는 전용 문법(Union[...])을 사용하는 것이 훨씬 빠르고 효율적입니다.
  2. 연산 복잡도: reduce는 매 단계마다 중간 객체를 생성할 가능성이 높지만, Union[args]는 인자들을 한 번에 처리하여 객체 생성 비용을 최소화합니다.

리뷰어 피드백

리뷰 과정에서 Union[...]의 잠재적 deprecation 논의가 있었으나, Union의 가변 인자 지원은 계속 유지될 것이라는 점이 확인되었습니다. 또한, | 연산자와 달리 Union[...]은 문자열 타입(ForwardRef) 처리 등에서 더 안전하고 일관된 동작을 보인다는 점이 장점으로 언급되었습니다.

참고 자료

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글