Skip to content

필사 모드: Python 타입 체커 2026 — Mypy·Pyright·Pylance·Pyre·Pyrefly·ty 비교 심층 가이드

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 — 2026년, Python에 정적 타입 체커가 너무 많아졌다

Python은 동적 언어로 시작했다. 그런데 2026년 현재, 산업 현장에서 Python을 짠다는 건 사실상 **타입 어노테이션을 짠다는 뜻**이다. FastAPI는 타입 힌트로 라우팅을 정의하고, Pydantic은 타입으로 데이터 검증을 하고, SQLAlchemy 2.0 ORM은 `Mapped[int]`로 컬럼을 선언한다. 타입이 없으면 현대 Python 라이브러리는 쓰기 어렵다.

문제는 **누가 그 타입을 검사하는가**다. 그리고 2025-2026년 사이에 이 질문의 답이 갑자기 복잡해졌다.

- **Mypy** — 2012년부터 있던 표준 구현. Dropbox 출신 Jukka Lehtosalo와 Guido van Rossum이 만들었다.

- **Pyright** — 2019년 Microsoft 발표. VS Code의 Pylance 엔진. IDE 피드백 최강.

- **Pyre** — Meta가 Instagram 모노레포를 위해 만든 OCaml 기반 체커. 점점 쇠퇴.

- **Pyrefly** — 2025년 Meta가 Pyre를 Rust로 다시 쓴 후속작. 모노레포에서 빠르다.

- **ty** — 2025년 Astral(uv·ruff 회사)이 발표한 Rust 기반 체커. 알파지만 빠르다.

- **Pytype** — Google이 만든 Python 2/3 추론 체커. 사용량 감소 중.

이 글은 2026년 5월 현재 이 도구들의 지도를 그린다. 누가 뭘 만들고 있고, soundness·speed·ergonomics가 어떻게 다르고, PEP 695·742 같은 최신 문법을 어디까지 따라가고, 점진적 도입을 어떻게 시작할지까지.

1장 · 2026년 Python 타입 체커 지도

먼저 큰 그림. 각 체커는 만든 곳·구현 언어·주력 사용처가 다르다.

| 체커 | 만든 곳 | 구현 언어 | 주력 사용처 | 2026년 상태 |

| --- | --- | --- | --- | --- |

| Mypy | Dropbox / Python 재단 | Python (compile to C via mypyc) | OSS 표준, 라이브러리 저자 | 안정, 표준 reference |

| Pyright | Microsoft | TypeScript / Node | IDE(Pylance), CI | 매우 활발 |

| Pylance | Microsoft (Pyright 기반) | TypeScript / Node | VS Code 전용 | Pyright의 IDE wrapper |

| Pyre | Meta | OCaml | Instagram 모노레포 | 유지보수 모드 |

| Pyrefly | Meta | Rust | Meta 모노레포·OSS | 2025년 OSS 공개, 빠르게 성장 |

| ty | Astral | Rust | uv 생태계 사용자 | 2025년 알파, 가속 중 |

| Pytype | Google | Python | Google 내부 | 사용량 감소, 유지보수만 |

지도에서 보이는 큰 트렌드 두 가지.

**첫째, Rust 재작성 물결.** Python 도구 체인은 지난 3년간 Rust로 옮겨 갔다. Ruff(린터)·uv(패키지 매니저)가 Astral의 트레이드마크가 됐고, 이제 타입 체커도 Rust로 가는 중이다. ty와 Pyrefly가 그 흐름의 대표. Mypy는 이미 mypyc(Python → C 컴파일러)를 통해 자기 자신을 컴파일하지만, Rust 네이티브에 비하면 여전히 느리다.

**둘째, IDE vs CLI 분리.** Pyright/Pylance는 LSP·incremental·watch 모드에 강점이 있다. Mypy는 batch CI 검사에 강점이 있다. 둘 다 쓰는 팀이 늘었다. ty와 Pyrefly가 이 두 시장을 동시에 노린다.

2장 · Python typing PEP 연대기 — 굵직한 변화

타입 체커를 비교하려면 먼저 **무엇을 체크해야 하는지** 정해진 PEP을 알아야 한다. 굵직한 것만 추렸다.

| PEP | 연도 | 내용 | Python 버전 |

| --- | --- | --- | --- |

| 484 | 2014 | 타입 힌트 도입 | 3.5 |

| 526 | 2016 | 변수 어노테이션 | 3.6 |

| 544 | 2017 | Protocol(구조적 부분 타이핑) | 3.8 |

| 561 | 2017 | 배포 시 타입 정보(py.typed) | 3.7 |

| 585 | 2019 | builtin 제네릭(`list[int]`) | 3.9 |

| 591 | 2019 | Final 한정자 | 3.8 |

| 593 | 2019 | Annotated | 3.9 |

| 604 | 2019 | `X` 파이프 `Y` 유니온 표기 | 3.10 |

| 612 | 2019 | ParamSpec | 3.10 |

| 646 | 2020 | TypeVarTuple | 3.11 |

| 647 | 2021 | TypeGuard | 3.10 |

| 673 | 2022 | Self 타입 | 3.11 |

| 675 | 2022 | LiteralString | 3.11 |

| 681 | 2022 | dataclass_transform | 3.11 |

| 692 | 2023 | TypedDict로 kwargs 타이핑 | 3.12 |

| 695 | 2022 | 새 제네릭 문법(`class Box[T]:`) | 3.12 |

| 696 | 2022 | TypeVar 기본값 | 3.13 |

| 698 | 2022 | `@override` 데코레이터 | 3.12 |

| 702 | 2023 | `@deprecated` 데코레이터 | 3.13 |

| 705 | 2023 | TypedDict readonly | 3.13 |

| 712 | 2023 | dataclass 변환 fields | (제안) |

| 728 | 2023 | TypedDict closed/extra_items | (제안) |

| 738 | 2024 | 새 PyOdide 관련(typing 외) | n/a |

| 742 | 2024 | TypeIs(향상된 narrowing) | 3.13 |

| 749 | 2024 | 어노테이션 lazy evaluation 명세 | (논의) |

| 750 | 2024 | t-string(typed string literal) | (제안) |

핵심 정리.

- **PEP 695 (3.12)**: 새 제네릭 문법이 들어왔다. `class Box[T]:` 처럼 클래스 옆에 직접 타입 매개변수를 적는다. TypeScript와 비슷해졌다.

- **PEP 696 (3.13)**: TypeVar 기본값. `Box[T = int]` 같은 표기가 가능.

- **PEP 742 (3.13)**: TypeGuard의 약점을 보완한 TypeIs. narrowing이 양방향으로 작동한다.

- **PEP 698 (3.12)**: `@override` 데코레이터. 메서드 오버라이드 검증.

- **PEP 749**: 어노테이션 평가 방식 정리. `from __future__ import annotations` 그 다음을 정의.

각 체커는 이 PEP 목록을 따라잡는 속도가 다르다. **Pyright가 가장 빠르고, Mypy가 가장 느리다.** ty와 Pyrefly는 신규 PEP을 처음부터 구현한다.

3장 · Mypy — 표준 reference 구현체

Mypy는 2012년에 시작했다. Jukka Lehtosalo의 박사 논문에서 출발해, Guido van Rossum이 Dropbox에서 합류한 뒤 본격화됐다. 2026년 현재 PEP 484의 사실상 reference 구현이다.

mypy의 검사 예제

from typing import Optional

def find_user(user_id: int) -> Optional[str]:

if user_id < 0:

return None

return "alice"

name = find_user(42)

print(name.upper()) # mypy 오류: name이 None일 수 있음

mypy를 돌리면 위 코드는 다음과 같이 잡힌다.

example.py:9: error: Item "None" of "Optional[str]" has no attribute "upper"

Found 1 error in 1 file (checked 1 source file)

**Mypy의 장점.**

1. **표준 동작.** typing 모듈 PEP의 reference 구현. 다른 체커는 mypy의 행동을 기준으로 비교당한다.

2. **풍부한 플러그인.** Django·SQLAlchemy·attrs 등 동적 동작이 많은 라이브러리용 플러그인 시스템이 잘 정립돼 있다.

3. **incremental cache.** `.mypy_cache/` 디렉토리에 결과를 저장해 두 번째 실행부터 빨라진다.

4. **mypyc로 자체 컴파일.** mypy 자체를 mypyc로 C 익스텐션화해 속도를 끌어올렸다.

**Mypy의 약점.**

1. **속도.** 모노레포에서 cold start가 느리다. 50만 줄 코드베이스에서 3-5분이 흔하다.

2. **신규 PEP 따라잡기.** PEP 695를 한참 만에 받았고, PEP 742(TypeIs)도 늦었다.

3. **에러 메시지.** "Argument 2 to ... has incompatible type" 같은 문구가 길고 난해할 때가 있다.

전형적인 `mypy.ini` 설정.

[mypy]

python_version = 3.13

strict = True

plugins = pydantic.mypy, sqlalchemy.ext.mypy.plugin

[mypy-tests.*]

disallow_untyped_defs = False

`strict = True`는 사실상 "모든 hardness를 켠다"는 의미다. 신규 코드는 strict로 시작하고, 레거시 코드는 모듈별로 풀어 주는 게 정석이다.

4장 · Pyright + Pylance — Microsoft, IDE 피드백 최강

Pyright는 2019년 Microsoft가 발표했다. TypeScript로 짜여졌고, Node.js에서 돈다. VS Code의 Python 확장 안에 Pylance라는 이름으로 들어가 있다.

Pyright의 설계 목표는 **incremental·즉각·정확**이다. 파일 하나 저장하면 0.1초 안에 결과가 나와야 한다. 이걸 위해 Pyright는 다음을 한다.

- **AST 캐싱.** 변경되지 않은 파일은 다시 파싱하지 않음.

- **Symbol 단위 incremental.** 함수 한 개만 바뀌면 그 함수의 의존성만 재검사.

- **inference의 적극성.** Mypy보다 더 적극적으로 타입을 추론한다(특히 type narrowing).

Pyright의 narrowing 예제

from typing import Union

def process(x: Union[int, str]) -> str:

if isinstance(x, int):

여기서 x는 int로 narrowing됨 — Mypy도 됨

return str(x * 2)

여기서 x는 str — Mypy도 됨

return x.upper()

기본 narrowing은 Mypy도 한다. 차이는 더 미묘한 경우에 나타난다.

Pyright는 narrowing하지만 Mypy는 못 하는 경우가 있다

from typing import Literal

def get_status() -> Literal["ok", "error"]:

...

s = get_status()

if s == "ok":

Pyright: s는 Literal["ok"]

Mypy: 같음 (둘 다 OK)

handle_ok()

**Pylance vs Pyright의 차이.**

- **Pyright**: 오픈소스. CLI·LSP·CI 어디서나 쓸 수 있다.

- **Pylance**: VS Code 전용 클로즈드 소스. Pyright 엔진 + VS Code 통합(자동 import·docstring 인레이·세션 캐시 등).

Pyright는 npm으로 받는다.

npm install -g pyright

pyright src/

설정은 `pyrightconfig.json` 또는 `pyproject.toml`의 `[tool.pyright]` 섹션.

{

"include": ["src"],

"exclude": ["**/node_modules", "**/__pycache__"],

"typeCheckingMode": "strict",

"pythonVersion": "3.13",

"reportMissingImports": "error",

"reportUnknownArgumentType": "warning"

}

`typeCheckingMode`는 `off`·`basic`·`standard`·`strict` 네 단계. `strict`는 Mypy의 `--strict`보다 더 빡빡한 경향이 있다.

5장 · Astral의 `ty` — Rust 기반, ruff·uv 만든 팀

Astral은 2024-2025년 사이 Python 도구 체인을 다시 썼다. Ruff(린터)·uv(패키지 매니저)가 압도적으로 빠르다는 게 입증된 뒤, 2025년 같은 팀이 **ty**라는 타입 체커를 알파로 공개했다.

ty의 설계 원칙.

1. **Rust 네이티브.** Mypy의 30-100배 빠른 cold start가 목표.

2. **incremental DB.** Salsa(rust-analyzer가 쓰는 incremental computation 프레임워크) 기반.

3. **LSP·CLI 양쪽.** Pyright처럼 IDE 통합이 일급 시민.

4. **ruff와 통합.** 같은 워크스페이스 설정·같은 캐시 디렉토리.

2026년 5월 현재 ty는 알파 단계지만, **신규 PEP 구현이 빠르다**. PEP 695는 출시 시점부터 지원했고, PEP 742·749도 이미 들어가 있다.

설치

uv tool install ty

검사

ty check src/

LSP 서버 띄우기

ty server

설정은 `pyproject.toml`의 `[tool.ty]` 섹션.

[tool.ty]

python-version = "3.13"

strict = true

exclude = ["tests/"]

[tool.ty.rules]

unresolved-import = "error"

unused-ignore-comment = "warning"

**ty가 던지는 위협.**

- 속도가 압도적. 50만 줄 모노레포에서 Mypy 3분 → ty 5초 같은 보고가 알파 단계에서 이미 나온다.

- ruff·uv 사용자에게는 도구 체인 통일의 매력. 셋 다 같은 회사·같은 캐시·같은 컨피그.

- 단, **plugin 시스템이 아직 없다**. SQLAlchemy 2.0·Pydantic 2 같은 동적 라이브러리는 정적 분석만으로 잡기 어려운 부분이 있다.

**2026년 5월의 현실.** ty는 신규 프로젝트나 작은 라이브러리에 좋다. 5만 줄 이상 SQLAlchemy 1.x 코드베이스를 ty로 검사하면 false positive가 쏟아진다. 1년 안에 안정화될 거라는 게 일반적 관측.

6장 · Meta `Pyrefly` — Pyre의 Rust 재작성

Meta는 Instagram·Facebook 백엔드에 1억 줄 단위의 Python 모노레포를 운영한다. Pyre는 이 모노레포를 위해 만든 OCaml 기반 체커였다. 그런데 OCaml 생태계가 점점 좁아지고, 모노레포의 incremental·distributed 요구가 커지자 Meta는 2024-2025년에 **Pyrefly**라는 Rust 재작성 후속작을 만들었다.

Pyrefly의 강점.

1. **모노레포 친화.** 분산 인덱싱·증분 검사·심볼 DB가 모노레포 스케일에서 검증됐다.

2. **type at scale.** 1억 줄에서 돈다는 게 메타 모노레포 내부에서 입증.

3. **OSS 공개.** 2025년에 OSS로 풀렸다. 메타 외부에서도 쓸 수 있다.

설치

cargo install pyrefly

또는

pip install pyrefly

검사

pyrefly check src/

Pyrefly의 설정은 `pyrefly.toml` 또는 `pyproject.toml`의 `[tool.pyrefly]`.

[tool.pyrefly]

python_version = "3.13"

project_root = "."

search_path = ["src", "lib"]

strict = true

**Pyrefly vs ty의 포지셔닝 차이.**

- **Pyrefly**: 모노레포 스케일이 먼저. Meta 내부 검증이 강점.

- **ty**: 일반 OSS·중소규모 프로젝트가 먼저. ruff·uv 생태계 통합이 강점.

둘 다 Rust지만 타깃 시장이 다르다. 작은 라이브러리 저자는 ty, Meta 같은 모노레포 운영자는 Pyrefly를 선호하는 패턴이 보인다.

7장 · Google `Pytype` — 사용량 감소하지만 여전

Pytype은 Google이 만들었다. 2015-2017년 사이 활발했고, Python 2/3 추론에 강점이 있었다. **타입 어노테이션 없이도 타입을 추론한다**는 게 차별점이었다.

Pytype은 어노테이션 없이도 추론한다

def add(x, y):

return x + y

Pytype: 사용처를 추적해 int·str·float 등의 가능성을 추정

add(1, 2) # int + int → int

add("a", "b") # str + str → str

**Pytype의 강점.**

1. 어노테이션이 없는 레거시 코드에 대한 추론 능력.

2. `.pyi` 스텁 파일을 자동 생성.

3. Google 내부에서 오래 검증.

**Pytype의 약점.**

1. **사용량 감소.** Google 내부에서도 Pyright·Pyrefly로 옮겨 가는 팀이 있다.

2. **신규 PEP 따라잡기.** PEP 695·742 같은 신규 문법 지원이 늦다.

3. **속도.** 모노레포에서 Mypy보다도 느리다는 보고가 있다.

2026년 현재 Pytype은 **신규 도입 추천 대상은 아니다**. 다만 Google·Apache Beam 같은 일부 대형 프로젝트가 여전히 쓰고 있어 완전히 사라지진 않을 것이다.

8장 · Soundness vs Speed vs Ergonomics — 4종 비교 표

타입 체커를 고를 때 보는 3개 축.

- **Soundness**: 잡아낼 수 있는 버그의 폭. "Mypy가 통과시키고 런타임에서 깨지는 코드"가 얼마나 적은가.

- **Speed**: cold start와 incremental 모두.

- **Ergonomics**: 에러 메시지·플러그인·LSP·문서.

2026년 5월 기준 주관적 평가.

| 체커 | Soundness | Cold Start 속도 | Incremental 속도 | LSP | 에러 메시지 | Plugin |

| --- | --- | --- | --- | --- | --- | --- |

| Mypy | 표준 | 느림 | 보통 | 별도 daemon 필요 | 길고 난해 | 풍부 |

| Pyright | 매우 강함 | 빠름 | 매우 빠름 | 일급 시민 | 짧고 명확 | 제한적 |

| Pyrefly | 강함 | 매우 빠름 | 매우 빠름 | 일급 시민 | 명확 | 미완성 |

| ty | 미완성 | 매우 빠름 | 매우 빠름 | 일급 시민 | 명확 | 없음 |

**이론적 soundness**는 Mypy가 표준이고 다른 체커는 그걸 reference로 친다. **실전 soundness**는 narrowing·overload·protocol 같은 미묘한 경우에서 갈린다.

**속도**는 Pyrefly·ty가 압도. 100만 줄 코드베이스에서 Mypy 5분 → Pyright 30초 → Pyrefly·ty 5초.

**에러 메시지**는 Pyright가 최고. Mypy는 길고, Pyrefly·ty는 명확하지만 초기 단계.

**Plugin**은 Mypy가 압도. 단, 신규 도구가 Pydantic 2·SQLAlchemy 2.0 같은 신규 라이브러리를 처음부터 잘 지원한다는 점은 흥미롭다.

9장 · PEP 695·TypeIs·Self·Never — 실전에서 자주 만나는 것들

2026년 Python 코드를 보면 PEP 484 시절과 문법이 많이 달라졌다. 자주 마주치는 것들.

PEP 695 — 새 제네릭 문법 (3.12+)

옛 문법(여전히 동작):

from typing import TypeVar, Generic

T = TypeVar("T")

class Box(Generic[T]):

def __init__(self, item: T) -> None:

self.item = item

새 문법(3.12+):

class Box[T]:

def __init__(self, item: T) -> None:

self.item = item

함수도 가능

def first[T](items: list[T]) -> T:

return items[0]

타입 별칭도

type StringList = list[str]

TypeScript와 비슷한 모양이 됐다. Pyright는 처음부터 지원했고, Mypy는 1.4부터 부분 지원, 1.7부터 안정. ty·Pyrefly는 출시 시점부터 지원.

PEP 742 — TypeIs (3.13+)

TypeGuard의 약점을 보완한 narrowing.

from typing import TypeIs

def is_str_list(val: list[object]) -> TypeIs[list[str]]:

return all(isinstance(x, str) for x in val)

def process(items: list[object]) -> None:

if is_str_list(items):

items는 list[str]로 narrowing

print(",".join(items))

else:

items는 여전히 list[object] (TypeGuard에서는 못 했던 일)

print("not strings")

`TypeIs`와 `TypeGuard`의 차이: `TypeIs`는 **양방향**으로 narrowing한다. else 분기에서도 "그것이 아닌 타입"이 살아남는다.

Self 타입 (PEP 673, 3.11+)

from typing import Self

class Builder:

def with_name(self, name: str) -> Self:

self.name = name

return self

def with_age(self, age: int) -> Self:

self.age = age

return self

class FancyBuilder(Builder):

def with_color(self, color: str) -> Self:

self.color = color

return self

Self 덕분에 체이닝이 서브클래스 타입을 유지

b = FancyBuilder().with_name("alice").with_color("red")

b: FancyBuilder (Self 덕에 Builder가 아님)

이전엔 `TypeVar` 트릭으로 했던 것을 `Self` 한 단어로 해결.

Never 타입

from typing import Never

def fail(msg: str) -> Never:

raise RuntimeError(msg)

def process(x: int | str) -> str:

if isinstance(x, int):

return str(x)

if isinstance(x, str):

return x

fail("unreachable") # 이 후 코드는 dead code로 표시됨

`Never`는 "이 함수는 반환하지 않는다"는 명시. 컴파일러가 dead code 분석에 활용.

`@override` 데코레이터 (PEP 698, 3.12+)

from typing import override

class Base:

def greet(self) -> str:

return "hello"

class Child(Base):

@override

def greet(self) -> str:

return "hi"

@override

def greeet(self) -> str: # 오타 — 부모에 없음, 체커가 잡음

return "hi"

TypeScript의 `override` 키워드와 같은 역할. 부모 클래스에 같은 이름의 메서드가 없으면 에러.

10장 · strict 모드와 점진적 타입 도입 전략

처음부터 strict로 시작할 수 있으면 좋지만, 기존 코드베이스는 그게 안 된다. 점진적 도입의 정석 패턴.

단계 1 — baseline 잡기

먼저 현재 상태에서 어떤 에러가 있는지 본다.

mypy --ignore-missing-imports src/ > baseline.txt

wc -l baseline.txt

이게 출발점. 새 PR은 이보다 늘리지 않는다는 규칙으로 시작.

단계 2 — 신규 코드는 strict

`mypy.ini`에서 새 모듈에만 strict를 적용.

[mypy]

python_version = 3.13

[mypy-myapp.new_module.*]

strict = True

[mypy-myapp.legacy.*]

ignore_errors = True

신규 코드는 처음부터 타이트하게. 레거시는 일단 무시.

단계 3 — `--strict-optional`만 먼저

`Optional[X]` vs `X`를 구분하는 게 가장 큰 가치를 준다. 다른 strict 플래그보다 먼저 켠다.

[mypy]

strict_optional = True

no_implicit_optional = True

이 두 개만 켜도 NPE 같은 None 관련 버그의 80%는 잡힌다.

단계 4 — `disallow_untyped_defs`

타입 없는 함수 정의를 금지.

[mypy]

disallow_untyped_defs = True

disallow_incomplete_defs = True

새 함수는 무조건 타입을 쓰게 강제. 기존 함수는 점진적으로 추가.

단계 5 — `strict = True`

모든 strict 플래그를 한 번에. 최종 단계.

[mypy]

strict = True

`strict = True`가 켜는 플래그.

- `disallow_untyped_defs`

- `disallow_any_generics`

- `disallow_untyped_calls`

- `disallow_incomplete_defs`

- `disallow_untyped_decorators`

- `check_untyped_defs`

- `no_implicit_optional`

- `warn_redundant_casts`

- `warn_return_any`

- `warn_unused_ignores`

- `strict_equality`

11장 · 실전 셋업 — pre-commit·CI·pytest 통합

pre-commit 훅

`.pre-commit-config.yaml`:

repos:

- repo: https://github.com/pre-commit/mirrors-mypy

rev: v1.13.0

hooks:

- id: mypy

additional_dependencies:

- "pydantic>=2.0"

- "sqlalchemy>=2.0"

args: ["--strict"]

- repo: https://github.com/RobertCraigie/pyright-python

rev: v1.1.380

hooks:

- id: pyright

두 체커를 같이 돌리는 패턴이 흔하다. Mypy는 깊이, Pyright는 속도.

GitHub Actions CI

`.github/workflows/typecheck.yml`:

name: typecheck

on: [pull_request]

jobs:

mypy:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-python@v5

with:

python-version: "3.13"

- run: pip install -e ".[dev]"

- run: mypy --strict src/

pyright:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-python@v5

with:

python-version: "3.13"

- run: pip install -e ".[dev]"

- run: pip install pyright

- run: pyright src/

pytest-mypy-plugins — 타입 자체를 테스트

타입 자체가 의도대로 작동하는지를 테스트하는 도구.

tests/typing/test_types.yml

- case: dict_lookup

main: |

from typing import TypedDict

class User(TypedDict):

name: str

age: int

user: User = {"name": "alice", "age": 30}

reveal_type(user["name"]) # N: Revealed type is "builtins.str"

reveal_type(user["age"]) # N: Revealed type is "builtins.int"

이런 yaml을 두면 pytest가 mypy를 돌려 `reveal_type` 출력이 기대값과 같은지 검증.

inline_snapshot — 타입 출력의 snapshot 테스트

`reveal_type` 출력을 snapshot으로 비교.

from inline_snapshot import snapshot

def test_types():

from mymodule import process

result = process(42)

assert type(result) == snapshot(int)

타입 변경이 의도된 것인지 의도되지 않은 것인지 PR diff에서 보임.

mypy daemon (dmypy)

대형 코드베이스에서 incremental 속도를 끌어올리는 방법.

데몬 시작

dmypy start -- --strict

검사 (캐시 살아있음)

dmypy check src/

상태 확인

dmypy status

종료

dmypy stop

VS Code에서 mypy를 쓰면 자동으로 dmypy를 띄우는 확장도 있다. Pyright의 LSP에 비하면 여전히 느리지만, batch mypy보다는 훨씬 빠르다.

12장 · 의사결정 가이드 — 우리 팀은 뭘 써야 하나

상황별 추천.

**Case 1 — 신규 OSS 라이브러리.**

- 메인: Pyright (CI에서)

- 보조: Mypy (배포 시 plugin 호환성 검증)

- 이유: Pyright가 빠르고 강하지만, OSS 사용자는 Mypy로 검사하니까 둘 다 통과해야 한다.

**Case 2 — Pydantic·FastAPI 백엔드.**

- 메인: Pyright + Pylance(VS Code)

- 보조: Mypy with pydantic.mypy plugin

- 이유: Pydantic 2는 Pyright와 잘 맞는다. Mypy는 plugin 필요.

**Case 3 — SQLAlchemy 2.0 + Django 모노레포.**

- 메인: Mypy with sqlalchemy.ext.mypy.plugin, django-stubs

- 보조: Pyright (IDE에서만)

- 이유: SQLAlchemy 1.x → 2.0 마이그레이션은 Mypy plugin이 핵심. Pyright는 일부 ORM 패턴을 못 잡는다.

**Case 4 — 신규 프로젝트, Astral 도구 체인.**

- 메인: ty

- 보조: Pyright (CI 보강)

- 이유: ruff·uv를 이미 쓰면 ty와의 통합이 자연스럽다. 알파지만 신규 프로젝트라면 false positive가 적다.

**Case 5 — 1억 줄 모노레포.**

- 메인: Pyrefly

- 보조: 없음

- 이유: Meta가 이 스케일에서 검증. 다른 체커는 OOM이 난다.

**Case 6 — 레거시 Python 2/3 혼합 코드.**

- 메인: Pytype (당분간만)

- 마이그레이션 후 Mypy 또는 Pyright로 이동

- 이유: Pytype은 어노테이션 없는 코드 추론이 강하다. 단, 신규 도입 추천은 아님.

13장 · 2026년 예측 — 1년 후 누가 살아남나

마지막으로 1년 후를 예측한다.

1. **Pyright는 IDE에서 표준을 유지한다.** Pylance의 VS Code 점유율이 이미 압도. 적이 없다.

2. **Mypy는 reference로 살아남는다.** Plugin 생태계가 너무 큰다. 죽지 않는다.

3. **ty가 가장 빠르게 성장한다.** Astral의 트랙 레코드(ruff·uv)가 신뢰를 주고, alpha → beta → stable이 1년 안에 일어날 가능성 높다.

4. **Pyrefly는 모노레포 전용 도구로 자리잡는다.** OSS에 풀렸지만 ty와 일반 시장은 겹치지 않는다.

5. **Pytype은 유지보수 모드로 머무른다.** 신규 도입 거의 없음.

6. **Pyre는 사실상 종료된다.** Pyrefly로의 완전 이전 발표가 1년 안에 나올 가능성.

가장 큰 와일드카드는 **ty의 plugin 시스템**이다. SQLAlchemy 2.0·Django 같은 동적 라이브러리를 ty가 처음부터 잘 잡으면 Mypy의 마지막 해자가 무너진다. 아니면 ty와 Mypy가 plugin 호환 레이어를 공유할 수도 있다. 어느 쪽이든 2027년 5월에는 풍경이 또 바뀔 것이다.

14장 · 참고 / References

공식 문서

- [Mypy documentation](https://mypy.readthedocs.io/)

- [Pyright documentation](https://microsoft.github.io/pyright/)

- [Pylance — VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance)

- [Pyre](https://pyre-check.org/)

- [Pyrefly (Meta)](https://github.com/facebook/pyrefly)

- [ty (Astral)](https://github.com/astral-sh/ty)

- [Pytype (Google)](https://github.com/google/pytype)

Typing PEP 모음

- [PEP 484 — Type Hints](https://peps.python.org/pep-0484/)

- [PEP 526 — Variable Annotations](https://peps.python.org/pep-0526/)

- [PEP 544 — Protocols](https://peps.python.org/pep-0544/)

- [PEP 561 — Distributing and Packaging Type Information](https://peps.python.org/pep-0561/)

- [PEP 585 — Builtin Generic Types](https://peps.python.org/pep-0585/)

- [PEP 604 — Union Operator](https://peps.python.org/pep-0604/)

- [PEP 612 — ParamSpec](https://peps.python.org/pep-0612/)

- [PEP 646 — TypeVarTuple](https://peps.python.org/pep-0646/)

- [PEP 673 — Self Type](https://peps.python.org/pep-0673/)

- [PEP 681 — dataclass_transform](https://peps.python.org/pep-0681/)

- [PEP 695 — Type Parameter Syntax](https://peps.python.org/pep-0695/)

- [PEP 696 — TypeVar Defaults](https://peps.python.org/pep-0696/)

- [PEP 698 — Override Decorator](https://peps.python.org/pep-0698/)

- [PEP 702 — Deprecated Decorator](https://peps.python.org/pep-0702/)

- [PEP 705 — TypedDict ReadOnly](https://peps.python.org/pep-0705/)

- [PEP 742 — TypeIs](https://peps.python.org/pep-0742/)

- [PEP 749 — Annotation Evaluation](https://peps.python.org/pep-0749/)

실전 도구

- [pytest-mypy-plugins](https://github.com/typeddjango/pytest-mypy-plugins)

- [pydantic.mypy plugin](https://docs.pydantic.dev/latest/integrations/mypy/)

- [sqlalchemy.ext.mypy.plugin](https://docs.sqlalchemy.org/en/20/orm/extensions/mypy.html)

- [django-stubs](https://github.com/typeddjango/django-stubs)

- [typeshed (표준 라이브러리 스텁)](https://github.com/python/typeshed)

배경 글

- [Python typing summit notes](https://github.com/python/typing/discussions)

- [Astral blog](https://astral.sh/blog)

- [Microsoft Pylance changelog](https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md)

현재 단락 (1/415)

Python은 동적 언어로 시작했다. 그런데 2026년 현재, 산업 현장에서 Python을 짠다는 건 사실상 **타입 어노테이션을 짠다는 뜻**이다. FastAPI는 타입 힌트로 ...

작성 글자: 0원문 글자: 15,749작성 단락: 0/415