엔지니어링

Nov 12, 2021

엔지니어링

Python 3.10 톺아보기

  • 김준기

    김준기

    창업멤버 / CTO

Nov 12, 2021

엔지니어링

Python 3.10 톺아보기

  • 김준기

    김준기

    창업멤버 / CTO

지난 10월 4일 Python의 3.10 새 버전이 발표되었습니다. Python은 2021년 10월 기준 TIOBE Index 기준으로 전 세계에서 가장 인기 있는 프로그래밍 언어입니다. 그만큼 새 버전에서 어떤 기능들이 추가되었는지에 대해서도 많은 분들이 관심을 가지고 계실 텐데요, Backend.AI 또한 Python을 주력 언어로 작성된 프로그램이니만큼 항상 관심 있게 지켜보고 있습니다. 이번 블로그 글에서는 Python 3.10의 주요 변화를 함께 살펴보는 시간을 갖고자 합니다.

구조적 패턴 매칭 (Structural Pattern Matching)과 with 구문의 확장

이번 릴리즈의 가장 하이라이트이자 근 수 년 사이 가장 주목할 만한 변화로는 구조적 패턴 매칭(Structural Pattern Matching) 문법의 추가입니다. Python 3.5 버전에서 async, await 키워드가 추가되고 3.8 버전에서 대입표현식을 위한 walrus 연산자(:=)가 추가된 이후 처음 도입되는 신규 문법이기도 하죠.

구조적 패턴 매칭은 단순하게는 C나 Java 언어의 switch-case와 같은 역할도 하지만, 값의 타입과 구조적 형태를 모두 고려한 매칭을 통해 훨씬 고도화된 분기문을 작성할 수 있게 해줍니다. 특히, 튜플의 요소 개수 및 타입, 딕셔너리의 키 종류 등의 구조적 정보를 통해 서로 다른 분기를 실행할 수 있다거나, 이 과정에서 as 구문으로 변수명을 지정하는 방식으로 매칭된 패턴 일부를 그대로 캡처하여 분기문 내에서 변수로 활용할 수 있다는 점이 다른 언어의 switch 구문과 비교했을 때 가장 두드러지는 차이점입니다. 예를 들면 문법 해석기(parser) 같은 것을 구현할 때도 추상 문법 트리(AST) 생성 코드를 아예 패턴 매칭 문법을 사용하여 EBNF 자체와 유사한 훨씬 간결한 코드로 표현하는 게 가능합니다.

def simplify_expr(tokens): match tokens: case [('(' | '[') as left, *expr, (')' | ']') as right] if (left + right) in ('()', '[]'): return simplify_expr(expr) case [0, ('+' | '-') as op, right]: return UnaryOp(op, right) case [ (int() | float() as left) | Num(left), '+', (int() | float() as right) | Num(right), ]: return Num(left + right) case [(int() | float()) as value]: return Num(value)

상세한 문법과 예제들은 일련의 PEP 문서(PEP-634, PEP-635, PEP-636)들을 통해 확인할 수 있습니다.

또 한 가지, 실무적으로 시스템 프로그래밍을 하는 입장에서 반길 만한 변화는 다중 context manager를 하나의 with 구문에 넣을 때 괄호로 묶어주는 것이 가능해졌다는 점입니다. 기존에는 이게 불가능했기 때문에 별도의 contextlib.ExitStack 객체로 묶어주거나, 들여쓰기를 불필요하게 중첩시키거나, 혹은 PEP-8 코드 스타일에서 권장하지 않는 backslash를 이용하여 여러 줄을 붙여주는 수밖에 없었습니다.

with ( Session(engine).begin() as session, contextlib.closing(some_file) as f, tempfile.NamedTemporaryFile() as t, ): # do something...

구조적 패턴 매칭을 위한 match 구문과 with 구문의 확장은 모두 Python 3.9에서 도입되어 3.10에서 기본으로 지정된 새로운 PEG 파서 덕분에 가능해진 것으로, 앞으로 Python 문법에서 더욱 다양한 변화나 개선 사항을 볼 수 있게 될 것으로 기대됩니다.

표준 라이브러리 개선사항들

이번 릴리즈에서는 제가 직접 소소하게 기여한 contextlib.aclosing() 함수도 추가되었습니다. contextlib.closing()의 async 버전에 대응하는 아주 간단한 패치입니다. 원래 관련 이슈인 bpo-41229는 async generator의 명시적 close 없이 코드를 실행하는 경우 async generator 객체들이 다음 번 이벤트 루프의 context switch가 발생하기 전까지 계속 메모리를 점유하고 있는 문제에 대한 보고였습니다. 실질적으로 asyncio로 장시간 도는 코드를 짰다면 context switch가 매우 빠른 시간 내에 발생할 것이므로 아주 영향이 큰 문제는 아니지만, 표준 라이브러리에 '표준적으로 권장되는 방법'으로 async generator를 명시적으로 닫아주는 패턴을 넣을 수 있다면 좋겠다고 생각하여 PR을 만들게 되었습니다.

타입 주석 지원 강화

이 외에도 귀도 반 로썸의 지속적인 참여로 개선 중인 타입 주석 관련 기능들도 새로이 추가되었습니다.

대표적으로 여러 개의 타입들을 모두 허용하는 Union 타입을 typing.Union[X, Y] 대신 X | Y로 간결하게 쓸 수 있게 되었다는 점입니다(PEP-604). 기존 Python 버전에서도 from __future__ import annotations 플래그를 설정하면 사용 가능했지만 3.10부터는 그렇게 하지 않아도 사용이 가능해졌습니다.

또한 typing.TypeAlias가 추가되어서 복잡한 타입 정의를 참조하는 이름을 정의하고자 할 때 그것이 새로운 타입 정의가 아닌 기존 타입의 별칭임을 명시적으로 표현할 수 있게 되었습니다(PEP-613). 언뜻 보기에는 별 차이가 없어보일 수 있지만, type checker가 보다 명확한 오류 메시지를 발생시키게 하거나 타입 정의를 실수로 실행하는 코드를 작성하는 것을 막을 수 있게 도와줍니다.

마지막으로는 decorator나 고차원 함수(함수를 입력으로 받거나 반환하는 함수)의 타입 정의를 엄밀하게 할 수 있는 typing.ParamSpectyping.Concatenate가 추가되었습니다(PEP-612). 기존에는 typing.Any로 표현할 수밖에 없었던 *args, **kwargs와 같은 패턴을 일종의 generic으로 정의해서 type argument로 취급함으로써 decorator의 입력과 반환 함수가 동일한 인자 형식을 갖도록 강제한다거나 특정 타입의 인자를 추가한다거나 이런 패턴들을 정확하게 표현할 수 있습니다.

그 다음은?

이렇게 살펴본 것처럼, Python 3.10은 구조적 패턴 매칭을 중심으로 문법과 타입 개선에 중점을 둔 릴리즈입니다.

내년 10월 릴리즈 예정인 3.11 버전과 그 이후 버전들은 성능 향상이 주요 개선 사항이 될 것으로 보이는데요, 특히 최근 Python 코어 개발자 커뮤니티에서는 보다 다양한 아이디어들을 실험하고 있습니다. 예를 들면 sub-interpreter를 도입하여 단일 프로세스 내에서 GIL을 다중화하여 분리하는 방식이나, 대부분의 오브젝트 referenc count 변경 시 실질적으로 lock이 필요하지 않다는 점에 착안하여 GIL을 제거하기 위한 biased reference counting 도입을 검토하고 있습니다. 물론 아직까지는 실험 단계이고 최종 버전에 언제 어떻게 반영될지는 확실하게 정해진 것이 아니지만, Python 언어의 창시자인 귀도 반 로썸이 최근 Microsoft로 이직한 이후 Microsoft의 지원을 받아 성능 개선팀을 꾸려 풀타임으로 개발을 진행 중이므로 1-2년 후에는 상당한 개선을 기대할 수 있을 것입니다.

앞으로 Backend.AI 또한 이러한 개선 사항들을 적극적으로 반영하여 보다 안정적이고 빠른 솔루션으로 거듭나고자 합니다.

도움이 필요하신가요?

내용을 작성해 주시면 곧 연락 드리겠습니다.

문의하기

본사 및 HPC 연구소

KR Office: 서울특별시 강남구 선릉로 577 CR타워 8층 US Office: 3003 N First st, Suite 221, San Jose, CA 95134

© Lablup Inc. All rights reserved.

개인정보를 소중히 여깁니다

사용자 경험 향상, 사이트 트래픽 분석 및 방문자 동향 파악을 위해 쿠키를 사용합니다. "모두 수락"을 클릭하면 쿠키 사용에 동의하는 것입니다. 자세히 보기