Python 3.15가 2026년 10월 9일 정식 릴리스되었습니다. 이번 업데이트는 언어 문법과 성능 최적화 측면에서 의미 있는 개선 사항들을 대거 선보였습니다. 특히 명시적 지연 임포트(lazy imports)는 대규모 애플리케이션의 고질적인 시작 지연 문제를 해결하며, frozendict의 내장 추가는 불변 매핑에 대한 오랜 갈증을 채워줍니다. 또한 컴프리헨션 언패킹으로 코드 작성이 한층 간결해졌으며, 프리 스레드(free-threaded) 빌드를 위한 안정 ABI 도입으로 진정한 멀티스레드 시대로 한 발짝 더 나아갔습니다. 이번 릴리스의 핵심 기능을 자세히 살펴보겠습니다.
PEP 810: 명시적 지연 임포트 (Explicit lazy imports)
대규모 Python 애플리케이션은 모듈 임포트가 연쇄적으로 발생하면서 애플리케이션 시작 속도가 크게 느려지는 문제에 자주 직면합니다. 그동안 개발자들은 함수 내부에 임포트 구문을 배치하거나 importlib을 활용해 필요 시점에 로딩하는 방식을 사용해 왔습니다. Python 3.15는 lazy 소프트 키워드를 도입하여 훨씬 우아한 해결책을 제공합니다.
lazy import를 사용하면 Python은 모듈을 즉시 로드하지 않고 경량 프록시 객체를 생성합니다. 해당 모듈의 속성이나 이름에 처음으로 접근할 때 비로소 실제 로딩이 실행됩니다.
lazy import json
lazy from pathlib import Path
print("Starting up...") # json과 pathlib은 아직 완전히 임포트되지 않음
data = json.loads('{"key": "value"}') # 첫 접근 시점에 json이 완전히 임포트됨
p = Path(".") # 첫 접근 시점에 pathlib이 완전히 임포트됨
지연 임포트 대상 모듈이 존재하지 않을 경우 첫 접근 시점에 예외가 발생합니다. 개발자는 환경 변수 PYTHON_LAZY_IMPORTS나 명령줄 옵션 -X lazy_imports를 통해 지연 임포트 동작을 전역적으로 제어할 수도 있습니다.
PEP 814: 신규 내장 타입 frozendict 추가
Python 3.15는 새로운 불변 내장 타입인 frozendict를 도입했습니다. 이 타입은 dict의 하위 클래스가 아니며 object를 직접 상속합니다. 키와 값이 모두 해시 가능(hashable)하다면 frozendict 자체도 해시 가능합니다. frozendict는 삽입 순서를 유지하지만, 동등성 비교(==) 시에는 순서를 고려하지 않습니다.
frozendict의 추가로 불변 매핑이 필요한 상황(딕셔너리의 키나 세트의 원소로 사용할 때)을 한층 깔끔하고 안전하게 다룰 수 있게 되었습니다.
>>> a = frozendict(x=1, y=2)
>>> a
frozendict({'x': 1, 'y': 2})
>>> a['z'] = 3
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
a['z'] = 3
~^^^^^
TypeError: 'frozendict' object does not support item assignment
>>> b = frozendict(y=2, x=1)
>>> hash(a) == hash(b)
True
>>> a == b
True
PEP 798: 컴프리헨션 언패킹 (Unpacking in comprehensions)
리스트, 세트, 딕셔너리 컴프리헨션과 제너레이터 표현식에서 * 및 **를 사용한 언패킹이 공식 지원됩니다. 이는 PEP 448 언패킹 문법의 자연스러운 확장으로, 여러 이터러블이나 딕셔너리를 하나의 평탄화된 구조로 결합할 때 중첩 컴프리헨션이나 itertools.chain()을 대체하는 간결한 방법을 제공합니다.
>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists] # [x for L in lists for x in L]와 동일
[1, 2, 3, 4, 5]
>>> sets = [{1, 2}, {2, 3}, {3, 4}]
>>> {*s for s in sets} # {x for s in sets for x in s}와 동일
{1, 2, 3, 4}
>>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
>>> {**d for d in dicts} # {k: v for d in dicts for k,v in d.items()}와 동일
{'a': 3, 'b': 2}
제너레이터 표현식에서도 동일하게 동작합니다:
>>> gen = (*L for L in lists) # (x for L in lists for x in L)와 동일
>>> list(gen)
[1, 2, 3, 4, 5]
PEP 661: 신규 내장 타입 sentinel 추가
Python 3.15는 builtins 모듈에 sentinel 타입을 추가하여, 명확하고 고유한 센티널 값을 표준 방식으로 생성할 수 있도록 지원합니다. 센티널 객체는 얕은 복사 시에도 식별성을 유지하고, 타입 표현식에서 | 유니온 연산자를 지원하며, 모듈과 이름으로 임포트 가능한 경우 pickle 직렬화도 지원합니다.
PEP 803: 프리 스레드 빌드를 위한 안정 ABI (abi3t)
프리 스레드(free-threaded) 환경을 대상으로 빌드되는 Python의 경우, C 확장이 새로운 전용 안정 ABI인 abi3t를 사용할 수 있게 되었습니다. abi3t를 적용하려면 PEP 697에서 도입된 API로 전환하고 PEP 793에서 추가된 새로운 모듈 익스포트 훅 PyModExport_*를 사용하는 등의 코드 수정이 필요합니다.
즉시 abi3t로 전환하기 어려운 확장의 경우, 기존 안정 ABI(abi3)와 버전별 프리 스레드 ABI(cp315t)를 각각 빌드하는 방식을 계속 유지해야 합니다.
업그레이드 권장사항 및 주의점
| 검토 기준 | 세부 설명 |
|---|---|
| 대상 사용자 | 애플리케이션 시작 속도 개선이 중요한 대규모 서비스 개발자, 복잡한 딕셔너리 병합 작업을 자주 처리하는 개발자, 프리 스레드 C 확장을 적극적으로 지원하려는 라이브러리 메인테이너. |
| 적용 시점 | 로컬 개발 및 테스트 환경에서는 즉시 Python 3.15를 도입해 테스트할 수 있습니다. 프로덕션 환경의 경우, 주요 의존성(특히 C 확장을 사용하는 라이브러리)이 abi3t 또는 cp315t를 지원할 때까지 기다린 후 마이그레이션하는 것을 권장합니다. |
| 주의사항 | • cProfile의 프로파일링 트레이스 기능이 새로운 profiling 모듈로 통합되었습니다 (PEP 799).• 기존 profile 모듈은 지원 중단(deprecated)되었으며 Python 3.17에서 완전히 제거될 예정입니다.• .pth 파일 내 import 구문 사용이 비공식적으로 사용 중단되었으며, 새로운 .start 설정 파일 사용이 권장됩니다 (PEP 829).• PyGILState 계열 API가 소프트 지원 중단(soft-deprecated)되어 향후 신규 API 추가가 중단됩니다 (PEP 788). |