모던 파이썬 기초 #1 시작과 uv 셋업
이 블로그에는 이미 파이썬 기초 강좌가 있습니다. 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가 무엇인가 #
uv는 Astral (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 install | uv init + uv add |
| lock 파일 | requirements.txt 직접 / poetry.lock | uv.lock 자동 |
| 표준 호환 | 도구마다 다름 | PEP 621 pyproject.toml 그대로 |
이 글에서는 uv를 기본으로 쓰고, 인터프리터,가상환경,의존성,실행을 모두 uv 한 손으로 해결합니다.
설치 #
macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | shHomebrew를 쓴다면:
brew install uvWindows (PowerShell):
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을 열어보면:
[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이 하는 일:
pyproject.toml의requires-python을 만족하는 인터프리터를 찾음 (없으면 자동 다운로드)- 프로젝트의 가상환경(
.venv/)을 자동으로 만들고uv.lock과 동기화 - 그 환경 안에서 명령을 실행
가상환경을 직접 활성화(source .venv/bin/activate)할 일이 없어집니다. 모든 명령 앞에 uv run을 붙이는 흐름으로 바뀝니다. 이게 적응이 좀 걸리지만, 한 번 익숙해지면 환경 활성화 까먹어서 시스템 파이썬에 패키지가 설치되는 사고가 사라집니다.
의존성 추가 #
패키지를 추가할 때는 uv add를 씁니다.
uv add httpx이 한 줄로 이런 일들이 동시에 일어납니다.
pyproject.toml의dependencies에httpx가 추가됨uv.lock에 정확한 버전과 해시가 기록됨.venv/에 설치됨
pyproject.toml을 다시 열어보면:
[project]
# ...
dependencies = [
"httpx>=0.28.1",
]개발 시점에만 필요한 도구(테스트 러너, 린터)는 --dev 그룹으로 분리합니다.
uv add --dev pytest ruff이러면 배포 시점에는 빠지고, 개발할 때만 설치됩니다. 패키지를 빼고 싶을 땐:
uv remove httpx한 번 더 — 흐름 전체 정리 #
# 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 기반이라 다른 머신에서도 정확히 같은 환경이 재현됩니다.
스크립트 단위로 쓰기 — 더 가벼운 경우 #
작은 스크립트 한 개만 돌리고 싶을 때, 프로젝트 셋업조차 부담이라면 스크립트 자체에 의존성을 적는 모드도 있습니다.
# /// script
# requires-python = ">=3.14"
# dependencies = ["httpx"]
# ///
import httpx
resp = httpx.get("https://httpbin.org/get")
print(resp.json())실행할 때:
uv run hello.pyuv가 # /// 안에 적힌 의존성을 인식해 임시 환경을 자동 구성하고 실행합니다. 일회용 스크립트, 자동화, 작은 도구를 만들 때 매우 유용합니다.
정리 #
이번 글에서 만든 흐름:
- 파이썬 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까지 짚습니다.