모던 파이썬 기초 #1 시작과 uv 셋업

5 분 소요

이 블로그에는 이미 파이썬 기초 강좌가 있습니다. 2017년에 시작한 시리즈고, Python 3.5~3.9 시점의 코드와 화면이 그대로 들어 있습니다. 그동안 파이썬은 많이 변했습니다. 그래서 구 강좌는 그대로 두고, 지금 다시 파이썬을 시작한다면 어떻게 할지를 7편으로 새로 정리합니다.

  • #1 시작과 uv 셋업 ← 이번 글
  • #2 변수/기본 타입과 타입 힌트
  • #3 제어 흐름 — if, while, for, match-case
  • #4 컬렉션과 컴프리헨션
  • #5 함수 — 인자 패턴
  • #6 에러와 예외 처리
  • #7 모듈/패키지와 pyproject.toml

왜 다시 파이썬? #

구 강좌가 쓰여질 때와 지금의 파이썬은 같은 언어라고 말하기 어색할 정도로 달라졌습니다. 큰 변화 몇 개만 추려도:

  • 타입 힌트가 표준 사용처가 됨. 라이브러리 코드 대부분이 타입을 가짐
  • match-case (3.10) — 자바스크립트 switch와는 결이 다른 패턴 매칭
  • 빌트인 제네릭 (3.9) — list[int], dict[str, int]를 그대로 쓸 수 있음
  • Union 단축 문법 (3.10) — Optional[int] 대신 int | None
  • exception group (3.11) — except*로 동시 발생 예외를 다룸
  • free-threaded (3.13~3.14, PEP 779) — GIL 없는 빌드가 정식 지원 단계로
  • t-string (3.14, PEP 765) — f-string과 다른, 보간이 지연되는 템플릿 리터럴
  • lazy annotations (3.14, PEP 649) — 어노테이션이 기본적으로 지연 평가됨

도구 체인도 거의 다 바뀌었습니다. pip 직접 호출, requirements.txt, virtualenv 수동 활성화 같은 옛 흐름은 이제 거의 쓰지 않습니다. 대신 한 가지 도구 — **uv**가 그 역할을 대부분 흡수합니다.

uv가 무엇인가 #

uvAstral (Ruff만든 곳)에서 만든 Rust 기반 파이썬 패키지,프로젝트 매니저입니다. 한 줄 요약은 이렇습니다.

pip + pip-tools + pipx + poetry + pyenv + virtualenv를 하나의 바이너리로 묶고, 10~100배 빠르게 만든 것.

왜 이게 표준이 되어 가는지 이유를 짧게:

기존 도구uv
속도수십 초~분수백 ms
파이썬 인터프리터 설치pyenv 별도uv python install 한 줄
프로젝트 셋업python -m venv + source .venv/bin/activate + pip installuv init + uv add
lock 파일requirements.txt 직접 / poetry.lockuv.lock 자동
표준 호환도구마다 다름PEP 621 pyproject.toml 그대로

이 글에서는 uv를 기본으로 쓰고, 인터프리터,가상환경,의존성,실행을 모두 uv 한 손으로 해결합니다.

설치 #

macOS / Linux:

install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

Homebrew를 쓴다면:

brew로 설치
brew install uv

Windows (PowerShell):

windows install
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

설치 후 새 터미널을 열고 버전을 확인하세요.

버전 확인
uv --version
# uv 0.5.x  (또는 그 이상)

파이썬 3.14 설치 #

uv는 파이썬 인터프리터까지 직접 설치합니다. pyenv가 따로 필요 없습니다.

파이썬 설치
uv python install 3.14

설치된 인터프리터 목록을 보려면:

설치된 파이썬 보기
uv python list --installed
# cpython-3.14.x-macos-aarch64-none ...

이 인터프리터는 시스템에 영구 설치된 것이지만, PATH에 직접 노출되지는 않습니다. uv가 프로젝트별로 알아서 골라 쓰는 구조입니다. 시스템의 다른 파이썬과 섞이지 않으니 안전합니다.

첫 프로젝트 #

빈 디렉터리를 만들고 uv init으로 프로젝트를 초기화합니다.

프로젝트 초기화
mkdir hello-py
cd hello-py
uv init --python 3.14

--python 3.14가 핵심입니다. 이 프로젝트는 3.14에 고정됩니다. 다른 프로젝트가 3.12를 써도 서로 간섭하지 않습니다. 명령을 실행하면 다음 파일들이 만들어집니다.

생성된 파일
hello-py/
├── .python-version    # 3.14
├── pyproject.toml     # 프로젝트 메타데이터 + 의존성
├── README.md
└── main.py            # print("Hello from hello-py!")

pyproject.toml을 열어보면:

pyproject.toml
[project]
name = "hello-py"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
dependencies = []

PEP 621 표준 형식 그대로입니다. 이 파일이 프로젝트의 단일 정의 라고 생각하면 됩니다. 의존성, 파이썬 버전, 빌드 정보, 도구 설정(ruff/mypy 등)이 전부 여기로 모입니다. requirements.txt, setup.py, setup.cfg는 이제 새로 만들 일이 거의 없습니다.

첫 실행 #

main.py를 그대로 실행해 봅시다. 다만 python main.py가 아니라 uv run main.py 입니다.

첫 실행
uv run main.py
# Hello from hello-py!

uv run이 하는 일:

  1. pyproject.tomlrequires-python을 만족하는 인터프리터를 찾음 (없으면 자동 다운로드)
  2. 프로젝트의 가상환경(.venv/)을 자동으로 만들고 uv.lock과 동기화
  3. 그 환경 안에서 명령을 실행

가상환경을 직접 활성화(source .venv/bin/activate)할 일이 없어집니다. 모든 명령 앞에 uv run을 붙이는 흐름으로 바뀝니다. 이게 적응이 좀 걸리지만, 한 번 익숙해지면 환경 활성화 까먹어서 시스템 파이썬에 패키지가 설치되는 사고가 사라집니다.

의존성 추가 #

패키지를 추가할 때는 uv add를 씁니다.

의존성 추가
uv add httpx

이 한 줄로 이런 일들이 동시에 일어납니다.

  • pyproject.tomldependencieshttpx가 추가됨
  • uv.lock에 정확한 버전과 해시가 기록됨
  • .venv/에 설치됨

pyproject.toml을 다시 열어보면:

추가된 dependencies
[project]
# ...
dependencies = [
    "httpx>=0.28.1",
]

개발 시점에만 필요한 도구(테스트 러너, 린터)는 --dev 그룹으로 분리합니다.

개발 의존성
uv add --dev pytest ruff

이러면 배포 시점에는 빠지고, 개발할 때만 설치됩니다. 패키지를 빼고 싶을 땐:

제거
uv remove httpx

한 번 더 — 흐름 전체 정리 #

zero-to-running 한 번에
# 1. 도구 설치 (한 번만)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. 프로젝트 만들기
uv init my-app --python 3.14
cd my-app

# 3. 의존성 추가
uv add httpx
uv add --dev pytest

# 4. 실행
uv run main.py
uv run pytest

여기까지가 옛날에 이런 분량이었습니다.

옛날 흐름 (참고)
# pyenv로 파이썬 설치
pyenv install 3.14.0
pyenv local 3.14.0

# venv 만들기
python -m venv .venv
source .venv/bin/activate

# 의존성 설치
pip install httpx
pip install pytest
pip freeze > requirements.txt

# 실행
python main.py

같은 일을 합니다만, lock 파일이 없어서 재현 가능성이 떨어지고, pip freeze는 직간접 의존성을 구분하지 못합니다. uv 쪽은 처음부터 lock 기반이라 다른 머신에서도 정확히 같은 환경이 재현됩니다.

스크립트 단위로 쓰기 — 더 가벼운 경우 #

작은 스크립트 한 개만 돌리고 싶을 때, 프로젝트 셋업조차 부담이라면 스크립트 자체에 의존성을 적는 모드도 있습니다.

hello.py
# /// script
# requires-python = ">=3.14"
# dependencies = ["httpx"]
# ///
import httpx

resp = httpx.get("https://httpbin.org/get")
print(resp.json())

실행할 때:

스크립트 단독 실행
uv run hello.py

uv가 # /// 안에 적힌 의존성을 인식해 임시 환경을 자동 구성하고 실행합니다. 일회용 스크립트, 자동화, 작은 도구를 만들 때 매우 유용합니다.

정리 #

이번 글에서 만든 흐름:

  • 파이썬 3.14가 가져온 변화 — 타입 힌트 우선, match-case, exception group, free-threaded, t-string
  • uv 한 도구로 인터프리터 설치 + 프로젝트 셋업 + 의존성 + 실행을 통합
  • uv init, uv add, uv run 세 명령이 일상 워크플로우
  • pyproject.toml이 프로젝트의 단일 정의
  • 가상환경 활성화 없는 흐름 — 모든 명령 앞에 uv run

다음 글(#2 변수/기본 타입과 타입 힌트)에서는 가장 기본 — 타입과 타입 힌트를 다룹니다. 동적 언어인데 왜 타입을 적는가, int | None 같은 모던 문법, list[int] 빌트인 제네릭, mypy/pyright까지 짚습니다.

X