본문으로 건너뛰기
Advertisement

모던 파이썬 — Python 3.10~3.13 신기능

Python 3.10부터 3.13까지 도입된 주요 신기능들을 실전 예제와 함께 살펴봅니다.


Python 3.10: 구조적 패턴 매칭(match-case)

# 기본 값 매칭
def classify_http_status(status: int) -> str:
match status:
case 200:
return "OK"
case 201:
return "Created"
case 400:
return "Bad Request"
case 401 | 403: # OR 패턴
return "인증/권한 오류"
case code if 500 <= code < 600: # 가드(guard) 조건
return f"서버 오류: {code}"
case _:
return "알 수 없는 상태"


print(classify_http_status(200)) # OK
print(classify_http_status(403)) # 인증/권한 오류
print(classify_http_status(503)) # 서버 오류: 503


# 시퀀스 패턴
def process_command(command: list[str]) -> str:
match command:
case ["quit"]:
return "종료"
case ["go", direction]:
return f"{direction}으로 이동"
case ["go", direction, speed]:
return f"{direction}으로 {speed} 속도 이동"
case ["help", *topics]:
return f"도움말: {', '.join(topics) or '전체'}"
case []:
return "빈 명령"
case _:
return f"알 수 없는 명령: {command}"


print(process_command(["go", "north"])) # 북쪽으로 이동
print(process_command(["go", "east", "fast"])) # 동쪽으로 fast 속도 이동
print(process_command(["help", "move", "look"])) # 도움말: move, look


# 매핑(dict) 패턴
def handle_event(event: dict) -> str:
match event:
case {"type": "click", "x": x, "y": y}:
return f"클릭: ({x}, {y})"
case {"type": "keypress", "key": key, "ctrl": True}:
return f"Ctrl+{key}"
case {"type": "keypress", "key": key}:
return f"키 입력: {key}"
case {"type": t, **rest}:
return f"알 수 없는 이벤트: {t}, 나머지: {rest}"


print(handle_event({"type": "click", "x": 100, "y": 200}))
print(handle_event({"type": "keypress", "key": "S", "ctrl": True}))


# 클래스 패턴
from dataclasses import dataclass


@dataclass
class Point:
x: float
y: float


@dataclass
class Circle:
center: Point
radius: float


@dataclass
class Rectangle:
top_left: Point
bottom_right: Point


def describe_shape(shape) -> str:
match shape:
case Circle(center=Point(x=0, y=0), radius=r):
return f"원점 중심 원, 반지름={r}"
case Circle(center=c, radius=r):
return f"원: 중심=({c.x},{c.y}), 반지름={r}"
case Rectangle(top_left=Point(x=x1, y=y1), bottom_right=Point(x=x2, y=y2)):
return f"직사각형: ({x1},{y1}) ~ ({x2},{y2})"


print(describe_shape(Circle(Point(0, 0), 5.0)))
print(describe_shape(Circle(Point(3, 4), 2.0)))
print(describe_shape(Rectangle(Point(0, 0), Point(10, 5))))

Python 3.10: X | Y 유니온 문법

# 기존: Union[str, None], Optional[str]
# 신규: str | None (Python 3.10+)

def find_user(user_id: int) -> dict | None:
users = {1: {"name": "Alice"}, 2: {"name": "Bob"}}
return users.get(user_id)


def process_value(value: int | str | list) -> str:
return str(value)


# 런타임에서도 isinstance와 함께 동작
def format_value(v: int | float | str) -> str:
if isinstance(v, int | float): # Python 3.10+: isinstance에서도 | 사용 가능
return f"{v:.2f}" if isinstance(v, float) else str(v)
return v.strip()


print(format_value(42)) # 42
print(format_value(3.14)) # 3.14
print(format_value(" hi ")) # hi


# 타입 별칭
Vector = list[float]
Matrix = list[Vector]
Scalar = int | float
Numeric = int | float | complex

Python 3.11: 예외 그룹과 ExceptionGroup

# Python 3.11+: ExceptionGroup — 여러 예외를 동시에 처리
def process_items(items: list[int]) -> list[int]:
errors = []
results = []

for item in items:
try:
if item < 0:
raise ValueError(f"음수 값: {item}")
if item == 0:
raise ZeroDivisionError("0으로 나누기")
results.append(100 // item)
except (ValueError, ZeroDivisionError) as e:
errors.append(e)

if errors:
raise ExceptionGroup("처리 오류", errors)
return results


try:
process_items([5, -3, 0, 2, -1])
except* ValueError as eg:
print(f"ValueError 발생 {len(eg.exceptions)}건:")
for e in eg.exceptions:
print(f" - {e}")
except* ZeroDivisionError as eg:
print(f"ZeroDivisionError 발생 {len(eg.exceptions)}건")


# Python 3.11+: add_note() — 예외에 메모 추가
try:
x = int("not_a_number")
except ValueError as e:
e.add_note("사용자가 입력한 값이 숫자가 아닙니다.")
e.add_note("올바른 형식: 1, 42, -5 등 정수만 허용")
raise

Python 3.11: Self 타입

from typing import Self
from __future__ import annotations # 이전 Python에서도 동작


class Builder:
def __init__(self) -> None:
self._parts: list[str] = []

def add(self, part: str) -> Self: # Self: 현재 클래스 타입 반환
self._parts.append(part)
return self

def build(self) -> str:
return " ".join(self._parts)


class ExtendedBuilder(Builder):
def add_many(self, *parts: str) -> Self: # Self: ExtendedBuilder 반환
for part in parts:
self.add(part)
return self


# 타입 추론 정확: ExtendedBuilder를 반환
builder = ExtendedBuilder()
result = builder.add("Hello").add_many("World", "!").build()
print(result) # Hello World !

Python 3.12: 타입 매개변수 문법 (PEP 695)

# Python 3.12+: 새로운 제네릭 문법
# 기존: from typing import TypeVar, Generic; T = TypeVar('T')
# 신규: type[T] 문법

# 함수 제네릭
def first[T](items: list[T]) -> T | None:
return items[0] if items else None


# 클래스 제네릭
class Stack[T]:
def __init__(self) -> None:
self._items: list[T] = []

def push(self, item: T) -> None:
self._items.append(item)

def pop(self) -> T:
return self._items.pop()


# 타입 별칭 (Python 3.12+)
type Vector = list[float]
type Matrix = list[Vector]
type Callback[T] = (T) -> None


# 제약이 있는 TypeVar
def double[T: (int, float)](x: T) -> T:
return x * 2


print(double(5)) # 10
print(double(3.14)) # 6.28

Python 3.12: @override 데코레이터

from typing import override


class Animal:
def speak(self) -> str:
return "..."

def move(self) -> str:
return "이동"


class Dog(Animal):
@override
def speak(self) -> str: # 타입 체커가 부모에 speak()가 있는지 확인
return "왈왈!"

@override
def moove(self) -> str: # 오타! 타입 체커가 경고
return "달린다!"

Python 3.13: 대화형 인터프리터 개선 & 기타

# Python 3.13: copy.replace() — 불변 객체 수정
import copy
from dataclasses import dataclass


@dataclass(frozen=True)
class Point:
x: float
y: float


p = Point(1.0, 2.0)
p2 = copy.replace(p, x=10.0) # 새 Point(10.0, 2.0) 반환
print(p) # Point(x=1.0, y=2.0)
print(p2) # Point(x=10.0, y=2.0)


# Python 3.11+: tomllib — TOML 파싱 표준 라이브러리
import tomllib

toml_content = b"""
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "테스트 프로젝트"

[tool.poetry.dependencies]
python = "^3.12"
pydantic = "^2.0"

[database]
host = "localhost"
port = 5432
name = "mydb"
"""

config = tomllib.loads(toml_content.decode())
print(f"프로젝트: {config['tool']['poetry']['name']}")
print(f"DB 호스트: {config['database']['host']}")


# pyproject.toml 파일 읽기 예시
# with open("pyproject.toml", "rb") as f:
# config = tomllib.load(f)

버전별 신기능 정리

# Python 3.10 주요 신기능
# - match-case 구조적 패턴 매칭 (PEP 634)
# - X | Y 유니온 타입 문법 (PEP 604)
# - 더 친절한 오류 메시지 (SyntaxError 등)
# - parenthesized context managers: (with a as x, b as y:)

# Python 3.11 주요 신기능
# - ExceptionGroup + except* (PEP 654)
# - Self 타입 (PEP 673)
# - LiteralString 타입 (PEP 675)
# - Required/NotRequired for TypedDict (PEP 655)
# - 성능 대폭 향상 (평균 25% 빠름, CPython 최적화)
# - tomllib 표준 라이브러리 추가 (PEP 680)

# Python 3.12 주요 신기능
# - 새 제네릭 문법: type aliases, type[T], TypeVarTuple (PEP 695)
# - @override 데코레이터 (PEP 698)
# - f-string 표현식 개선 (따옴표, 여러 줄 허용)
# - 성능 추가 개선

# Python 3.13 주요 신기능
# - 개선된 대화형 인터프리터 (컬러 출력, 멀티라인 편집)
# - copy.replace() (PEP 759)
# - JIT 컴파일러 실험적 지원
# - GIL 제거 실험적 지원 (free-threaded CPython, PEP 703)

고수 팁: f-string 개선 (Python 3.12+)

# Python 3.12+: f-string 안에 같은 따옴표 사용 가능
items = ["apple", "banana", "cherry"]

# 이전 버전: 따옴표 충돌로 불편
# result = f"아이템: {', '.join(items)}"

# Python 3.12+: 같은 따옴표 OK
result = f"아이템: {", ".join(items)}"
print(result)

# f-string 안에서 백슬래시 허용
path = f"경로: {"\n".join(["/usr", "/bin", "/etc"])}"

# 중첩 f-string
value = 42
msg = f"값: {f"{value:08b}"} (이진수)" # 값: 00101010 (이진수)
print(msg)

정리

버전주요 기능키워드
3.10구조적 패턴 매칭match-case
3.10유니온 타입 단축X | Y
3.11다중 예외 처리ExceptionGroup, except*
3.11셀프 타입 반환Self
3.11TOML 파싱tomllib
3.12제네릭 문법 간소화type[T], type 별칭
3.12오버라이드 검증@override
3.13실험적 JIT/GIL-free성능 향상

모던 파이썬은 타입 안전성, 표현력, 성능 세 방향으로 꾸준히 발전하고 있습니다.

Advertisement