본문으로 건너뛰기
피드

Python 3.15에서 헤드라인은 못 탔지만 꽤 쓸만한 기능들

backend 약 7분
vote
0
댓글
북마크

Python 3.15에는 lazy imports나 Tachyon profiler 같은 큰 기능 말고도 실무에서 바로 체감될 만한 작은 개선들이 들어가. TaskGroup 취소, 컨텍스트 매니저 데코레이터 개선, 스레드 안전 이터레이터처럼 평소 애매하게 불편했던 지점들이 꽤 깔끔해졌어.

  • 1

    asyncio TaskGroup에 예외 없이 그룹을 취소하는 cancel 기능이 추가됨

  • 2

    ContextDecorator가 제너레이터·코루틴·비동기 제너레이터의 전체 수명주기를 감싸도록 개선됨

  • 3

    threading.serialize_iterator로 이터레이터를 스레드 안전하게 감쌀 수 있음

  • 4

    collections.Counter에 xor 연산이 추가됨

  • 5

    frozendict 추가로 JSON 타입 전체를 불변·해시 가능 형태로 표현할 수 있게 됨

  • Python 3.15는 큰 기능만 있는 릴리스가 아님.
    • lazy imports나 Tachyon profiler처럼 눈에 띄는 기능도 있지만, 이번 글은 헤드라인을 못 탄 작은 변화들을 훑음.
    • 작은 기능이라도 실무에서 반복적으로 밟던 발목 지점을 없애는 경우가 있어서, 이런 게 은근 오래 감.

asyncio 쪽은 TaskGroup 취소가 깔끔해짐

  • Python 3.15에서는 asyncio TaskGroup을 더 우아하게 취소할 수 있음.

    • TaskGroup은 여러 비동기 작업을 구조적으로 묶어 실행하는 기능.
    • 기존에는 그룹 실행 중 어떤 신호를 받아 전체를 멈추려면, 커스텀 예외를 던지고 ExceptionGroup에서 걸러내는 식의 우회가 필요했음.
  • 새 TaskGroup.cancel은 그 우회를 없애줌.

    • 그룹 안의 작업을 취소하되, 일부러 예외를 만들어 흐름 제어에 쓰지 않아도 됨.
    • “설명할 게 거의 없을 만큼 단순하다”는 원문 표현이 딱 맞는 변화.

💡

> asyncio 코드에서 TaskGroup 종료를 위해 커스텀 예외를 던지고 suppress로 걸러내던 패턴이 있다면, Python 3.15부터는 TaskGroup.cancel로 단순화할 여지가 있음.

컨텍스트 매니저 데코레이터가 제너레이터 수명주기까지 감쌈

  • Python에서는 컨텍스트 매니저를 데코레이터처럼 쓸 수 있음.

    • 예를 들어 특정 블록의 실행 시간을 재는 컨텍스트 매니저를 함수 데코레이터로 붙이는 식.
    • 이 기능 자체는 Python 3.3부터 가능했음.
  • 문제는 이 방식이 이터레이터, 비동기 함수, 비동기 이터레이터에서는 잘 안 맞았다는 점.

    • 일반 함수는 호출 시 실제 실행이 바로 일어나지만, 제너레이터 함수는 호출하면 제너레이터 객체만 반환하고 본문 실행은 나중에 시작됨.
    • 코루틴 함수와 비동기 제너레이터도 비슷하게 “호출 시점”과 “실제 실행 수명주기”가 분리됨.
    • 그래서 데코레이터가 감싸야 할 전체 작업이 아니라 객체 생성 순간만 감싸고 끝나는 함정이 생겼음.
  • Python 3.15의 ContextDecorator는 감싸는 함수의 타입을 확인해 전체 수명주기를 덮도록 바뀜.

    • 이터레이터면 반복이 끝날 때까지, 코루틴이면 await가 끝날 때까지, 비동기 제너레이터면 비동기 반복 수명까지 커버하는 식.
    • 글쓴이는 이 변화 덕분에 컨텍스트 매니저가 데코레이터를 만드는 가장 좋은 방법이 됐다고 평가함. 살짝 과감한 주장인데, 발목 포인트가 줄어든 건 맞음.

스레드 안전 이터레이터가 표준 라이브러리에 들어옴

  • Python 이터레이터는 기본적으로 스레드 안전하지 않음.

    • 여러 스레드가 같은 이터레이터를 동시에 소비하면 값이 건너뛰어지거나 내부 상태가 깨질 수 있음.
    • free-threading 쪽 흐름까지 생각하면 이 문제가 더 중요해짐.
  • Python 3.15에는 threading.serialize_iterator가 추가됨.

    • 기존 이터레이터를 감싸서 여러 스레드가 안전하게 값을 하나씩 가져가도록 만듦.
    • generator 함수 결과에 이 처리를 적용하는 threading.synchronized_iterator 데코레이터도 있음.
  • threading.concurrent_tee도 추가됨.

    • 값을 나눠 갖는 게 아니라, 여러 이터레이터에 같은 값을 복제해 전달하는 용도.
    • 예전에는 이런 동기화를 하려면 Queue 중심으로 구조를 바꾸는 일이 많았는데, 이제 이터레이터 추상화를 유지한 채 해결할 수 있는 선택지가 생김.

보너스 기능도 소소하게 흥미로움

  • collections.Counter에 xor 연산이 들어감.

    • Counter는 단순 빈도 카운터처럼 보이지만, 집합처럼 교집합·합집합류 연산도 제공해 왔음.
    • Python 3.15에서는 대칭 차집합에 해당하는 xor까지 추가됨.
    • 글쓴이는 실제 사용처가 바로 떠오르진 않지만, 완성도 측면에서는 납득된다는 반응.
  • frozendict 추가로 JSON 타입 전체를 불변·해시 가능 형태로 표현할 수 있게 됨.

    • JSON의 배열, 불리언, 숫자, null, 문자열은 이미 불변 표현이 가능했지만 객체는 일반 dict라 해시 불가능했음.
    • frozendict가 들어오면서 JSON object까지 불변 구조로 다룰 수 있게 됨.

기술 맥락

  • 이번 변화들은 대부분 “새로운 패러다임”보다는 기존 추상화의 빈틈을 메우는 쪽이에요. TaskGroup, ContextDecorator, iterator는 이미 많이 쓰이는데, 특정 상황에서만 갑자기 복잡해지는 부분이 있었거든요.

  • TaskGroup.cancel이 중요한 이유는 예외를 흐름 제어용으로 덜 쓰게 해준다는 점이에요. 비동기 코드에서 ExceptionGroup까지 얽히면 디버깅이 금방 피곤해지는데, 취소 의도를 API로 직접 표현하면 코드 읽는 사람이 훨씬 덜 헷갈려요.

  • ContextDecorator 개선은 라이브러리 작성자에게 특히 의미가 있어요. 데코레이터 하나가 일반 함수와 제너레이터, 비동기 함수에서 다르게 동작하면 사용자는 버그를 자기 코드 문제로 오해하기 쉽거든요.

  • 스레드 안전 이터레이터는 free-threading 시대를 준비하는 성격도 있어요. 이터레이터라는 깔끔한 추상화를 유지하면서 동시 소비를 안전하게 만들 수 있으니, 기존 코드를 Queue 중심으로 크게 바꾸지 않아도 되는 장점이 있어요.

Python 3.15의 작은 기능들은 화려하진 않지만, 라이브러리 작성자나 동시성 코드를 만지는 사람에겐 꽤 반가운 변화야. 특히 컨텍스트 매니저를 데코레이터로 쓸 때 생기던 수명주기 함정이 줄어든 건 실무 버그를 조용히 줄여줄 가능성이 큼.

댓글

댓글

댓글을 불러오는 중...

backend

클릭하우스가 PgBouncer 처리량을 4배로 끌어올린 방법

ClickHouse Managed Postgres 팀은 단일 스레드인 PgBouncer를 여러 프로세스로 띄우고 `so_reuseport`와 피어링(peering)을 조합해 16 vCPU 머신을 제대로 쓰게 만들었다. 동일한 AWS 환경에서 단일 프로세스는 약 8.7만 TPS 근처에서 막혔지만, 16개 프로세스 구성은 약 33.6만 TPS까지 올라갔다.

backend

SQLite 쓸 거면 STRICT 테이블을 기본값으로 보자는 주장

SQLite의 STRICT 테이블은 INTEGER 컬럼에 문자열이 들어가는 식의 타입 실수를 막아주는 기능이다. 글쓴이는 SQLite 특유의 유연한 타입 시스템보다, 실수는 빨리 터뜨리는 쪽이 실무에서 낫다고 주장한다. 다만 기존 테이블을 바로 STRICT로 바꾸기 어렵고, SQLite 3.37.0 이상에서만 쓸 수 있다는 제약도 있다.

backend

왜 아직도 Lisp를 배워볼 만한가

Lisp는 괄호가 많은 이상한 언어처럼 보이지만, 핵심은 문법이 아니라 언어 자체를 확장할 수 있다는 점에 있음. 매크로, 코드-데이터 동일성, REPL 중심 개발이 합쳐지면 프로그램을 '작성'한다기보다 살아 있는 시스템을 계속 진화시키는 방식으로 개발하게 됨.

backend

EDB 포스트그레스 AI, 포레스터 멀티모델 데이터 플랫폼 리더 선정

EDB의 AI 데이터 플랫폼 EDB 포스트그레스 AI가 2026년 2분기 포레스터 웨이브 멀티모델 데이터 플랫폼 보고서에서 리더로 선정됐음. 트랜잭션, 분석, AI 워크로드를 하나의 플랫폼에서 다루는 흐름이 강해지는 가운데, EDB는 전략과 현재 제공 기능 모두에서 높은 평가를 받았다고 밝힘.

backend

Bun, Zig에서 Rust로 갈아탔다: 11일짜리 초대형 런타임 포팅 실험

Bun 팀이 53만 줄이 넘는 Zig 코드베이스를 Rust로 기계적으로 포팅했고, Bun v1.4.0부터 Rust 기반으로 전환될 예정임. 핵심 이유는 성능보다 안정성이었고, use-after-free, double-free, 메모리 누수 같은 문제를 컴파일러와 타입 시스템으로 더 빨리 잡기 위해서였음. Claude Code 워크플로 64개를 병렬로 돌려 11일 만에 전 플랫폼 테스트 통과까지 밀어붙인 사례라, LLM 기반 대규모 코드 마이그레이션의 꽤 강한 신호탄임.