본문 바로가기
C.W.K.
Stream
Lesson 02 of 05 · published

Literal·Final·ClassVar·Annotated — 더 정확한 의도

~18 min · literal, final, classvar, annotated

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

Literal은 허용할 정확한 값의 집합을, Final은 다시 묶거나 덮어쓸 의도가 없음을, ClassVar는 인스턴스 필드가 아닌 공유 클래스 값을 나타내. Annotated는 기본 타입에 검증·문서 도구가 읽을 메타데이터를 붙여.

이 표시는 정적 계약이라 실행 중 재할당을 막지 않아. 실제 강제가 필요하면 property, frozen dataclass, Pydantic 같은 경계를 따로 써.

Code

정확한 값만 허용하는 Literal·python
from typing import Literal

Mode = Literal["r", "w", "a", "r+"]

def open_file(path: str, mode: Mode = "r") -> str:
    return f"opening {path} in {mode}"

open_file("x.txt", "r")     # OK
open_file("x.txt", "w")     # OK
# open_file("x.txt", "x")   # mypy 에러: Literal['r', 'w', 'a', 'r+'] 기대

# Literal 이 int, bool, None 에도 작동
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
MaybeOn = Literal[True, False]
재할당 의도를 막는 Final·python
from typing import Final

# 모듈 레벨 상수
MAX_RETRIES: Final = 3
# MAX_RETRIES = 5     # mypy 에러: final 이름에 할당 불가

# 클래스 속성
class Config:
    VERSION: Final = "1.0.0"
    TIMEOUT: Final[int] = 30

# 서브클래싱도 표시
# class SubConfig(Config):
#     VERSION = "2.0"   # mypy 에러: final 속성 override 불가

# sentinel, 설정 상수, 의도상 immutable 한 모든 것에 유용
공유 클래스 값인 ClassVar·python
from typing import ClassVar
from dataclasses import dataclass

@dataclass
class User:
    name: str                          # 인스턴스 속성
    age: int                           # 인스턴스 속성
    DEFAULT_ROLE: ClassVar[str] = "member"   # 클래스 속성, 공유

u = User("alice", 30)
print(u.name)
print(u.DEFAULT_ROLE)                   # 'member' — 인스턴스로 접근
print(User.DEFAULT_ROLE)                # 클래스로도

# ClassVar 없으면 dataclass 가 DEFAULT_ROLE 을 인스턴스 필드로 처리
# + __init__ 에 요구 — 잘못된 동작.
타입에 메타데이터 붙이는 Annotated·python
from typing import Annotated

# 그냥 int — 추가 정보 없음
def plain(x: int) -> int:
    return x

# 제약 가진 Annotated int
UserId = Annotated[int, "사용자 유니크 식별자", "양의 정수"]

def with_meta(uid: UserId) -> str:
    return f"user {uid}"

# 런타임에 UserId 는 그냥 int
print(with_meta(42))                    # 'user 42'

# 메타데이터는 typing.get_type_hints / typing.get_args 로 접근
from typing import get_type_hints, get_args
hints = get_type_hints(with_meta, include_extras=True)
print(hints["uid"])
print(get_args(hints["uid"]))

External links

Exercise

다섯 로그 수준의 Literal을 만들고 log(message, level='INFO')에 써. Config에는 VERSION: Final과 MAX_RETRIES: ClassVar를 두고 잘못된 수준과 VERSION 재할당을 타입 검사기가 잡는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.