Python 환경 관리는 인터프리터 버전 선택과 프로젝트 의존성 격리를 분리해서 생각하면 단순해진다. `pyenv` 같은 버전 관리 도구로 인터프리터를 선택하고, Python 표준 라이브러리의 `venv`로 프로젝트 전용 환경을 만든다.
이 글은 2026년 8월 1일 [Python `venv` 문서](https://docs.python.org/3/library/venv.html)와 [Python Packaging User Guide](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/)를 기준으로 확인했다.
## 권장 기준선
Python 프로젝트가 현재 지원하는 버전을 선택한 뒤 프로젝트 루트에서 실행한다.
```bash
python3 --version
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
```
활성화는 편의를 위한 절차이지 필수 조건은 아니다. 자동화에서는 `.venv/bin/python`을 직접 호출할 수 있다. `.venv/`는 Git에서 제외하고, 환경 디렉터리 대신 프로젝트 메타데이터나 검토된 requirements 입력 파일에 의존성을 기록한다.
## 도구 선택 기준
- 최소한의 표준 기능이면 `venv`를 사용한다.
- 프로젝트마다 Python 버전이 다르면 `pyenv`를 고려한다. `.python-version` 공유 여부는 팀 규칙으로 결정한다.
- 잠금, 배포, 작업 실행 기능이 필요하면 Hatch, PDM, Pipenv, Poetry, uv 등을 요구사항에 맞춰 고른다. PyPA는 하나의 범용 도구를 정답으로 지정하지 않는다.
- 독립 실행형 Python CLI는 `pipx`로 설치해 도구별 환경을 분리한다.
## 기존 프로젝트 이전
1. 필요한 Python 버전과 지원 상태를 확인한다.
2. 기존 환경을 지우기 전에 의존성 선언을 보존한다.
3. 선택한 인터프리터로 `.venv`를 만든다.
4. 선언된 의존성을 설치한다.
5. 테스트와 실제 시작 명령을 실행한다.
기존 가상 환경의 인터프리터를 제자리에서 업그레이드할 수 있다고 가정하지 않는다. 환경을 다시 만들고 검증하는 편이 안전하다.
## 이전 방식이 달라진 이유
Python 2는 2020년에 지원이 끝났고, 현대적인 안내에서 사용하는 Python 3 표준 `venv` 모듈을 제공하지 않았다. 따라서 `python2 -m venv`는 이식 가능한 기준선이 아니었다. 과거 예제는 운영체제 Python, Homebrew Python, 버전 관리자, 프로젝트 패키지를 한 흐름에 섞으면서 각 층의 소유권을 설명하지 않는 경우도 많았다.
경계를 명확히 유지한다. 운영체제나 package manager는 자신이 설치한 Python을 소유한다. 버전 관리자는 개발용 인터프리터를 추가로 설치할 수 있다. 프로젝트는 의존성 선언을 소유하고, 재생성 가능한 가상 환경은 설치 결과를 담는다. 프로젝트를 실행하기 위해 `sudo pip install`을 사용하거나, 환경 생성을 피하려고 externally managed system interpreter를 수정하지 않는다.
## 재현 가능한 프로젝트 예제
작은 애플리케이션도 `pip freeze` 결과를 설계 의도로 간주하기보다 직접 의존성과 build metadata를 `pyproject.toml` 등에 선언한다. 구체적인 형식은 선택한 build backend에 따라 달라진다. 저장소가 workflow를 정했다면 하나의 bootstrap 명령을 문서화하고 CI에서도 같은 방식을 사용한다.
```bash
git clone https://example.com/team/project.git
cd project
pyenv install --skip-existing 3.13.5
pyenv local 3.13.5
python -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m pytest
```
위 버전은 예시일 뿐 영구적인 권장 버전이 아니다. 선택 전에 [Python 버전 현황](https://devguide.python.org/versions/)과 프로젝트의 지원 범위를 확인한다. CI에서는 개발자의 `.venv`를 복사하지 말고 지원하는 Python 버전마다 새 환경을 만든다.
## 자주 만나는 실패
- `python`이 계속 `.venv` 밖을 가리키면 `command -v python`을 확인하고 환경 내부 interpreter의 절대 경로를 사용한다.
- native extension 빌드가 실패하면 compiler와 운영체제 라이브러리 전제 조건을 확인한다. 환경 재생성만으로 system library가 생기지는 않는다.
- 개발자마다 다른 버전이 해결되면 환경 디렉터리를 주고받지 말고 프로젝트가 선택한 lock 또는 constraints workflow를 도입한다.
- 독립 CLI가 프로젝트 의존성과 충돌하면 프로젝트 환경이 아니라 `pipx`로 설치한다.
- `.venv`를 복사했거나 interpreter 위치가 바뀌었다면 다시 만든다. 가상 환경은 보통 폐기 후 재생성하는 대상이며 이식 가능한 archive가 아니다.
활성화 script는 shell code를 실행한다. 자신이 통제하는 환경이 만든 script만 사용하고 신뢰할 수 없는 archive에서 받은 환경을 source하지 않는다.
## 검증
```bash
python -c 'import sys; print(sys.executable); print(sys.version)'
python -m pip check
```
실행 경로가 `.venv` 아래를 가리키고 `pip check`가 깨진 요구사항을 보고하지 않아야 한다.
마지막으로 저장소의 전체 test, lint, type check, build, smoke test를 실행한다. 깨끗한 시스템에서 같은 지원 절차를 재현할 수 있어야 환경 구성이 완료된 것이다.
Python 환경 관리는 인터프리터 버전 선택과 프로젝트 의존성 격리를 분리해서 생각하면 단순해진다. pyenv 같은 버전 관리 도구로 인터프리터를 선택하고, Python 표준 라이브러리의 venv로 프로젝트 전용 환경을 만든다.
활성화는 편의를 위한 절차이지 필수 조건은 아니다. 자동화에서는 .venv/bin/python을 직접 호출할 수 있다. .venv/는 Git에서 제외하고, 환경 디렉터리 대신 프로젝트 메타데이터나 검토된 requirements 입력 파일에 의존성을 기록한다.
도구 선택 기준
최소한의 표준 기능이면 venv를 사용한다.
프로젝트마다 Python 버전이 다르면 pyenv를 고려한다. .python-version 공유 여부는 팀 규칙으로 결정한다.
잠금, 배포, 작업 실행 기능이 필요하면 Hatch, PDM, Pipenv, Poetry, uv 등을 요구사항에 맞춰 고른다. PyPA는 하나의 범용 도구를 정답으로 지정하지 않는다.
독립 실행형 Python CLI는 pipx로 설치해 도구별 환경을 분리한다.
기존 프로젝트 이전
필요한 Python 버전과 지원 상태를 확인한다.
기존 환경을 지우기 전에 의존성 선언을 보존한다.
선택한 인터프리터로 .venv를 만든다.
선언된 의존성을 설치한다.
테스트와 실제 시작 명령을 실행한다.
기존 가상 환경의 인터프리터를 제자리에서 업그레이드할 수 있다고 가정하지 않는다. 환경을 다시 만들고 검증하는 편이 안전하다.
이전 방식이 달라진 이유
Python 2는 2020년에 지원이 끝났고, 현대적인 안내에서 사용하는 Python 3 표준 venv 모듈을 제공하지 않았다. 따라서 python2 -m venv는 이식 가능한 기준선이 아니었다. 과거 예제는 운영체제 Python, Homebrew Python, 버전 관리자, 프로젝트 패키지를 한 흐름에 섞으면서 각 층의 소유권을 설명하지 않는 경우도 많았다.
경계를 명확히 유지한다. 운영체제나 package manager는 자신이 설치한 Python을 소유한다. 버전 관리자는 개발용 인터프리터를 추가로 설치할 수 있다. 프로젝트는 의존성 선언을 소유하고, 재생성 가능한 가상 환경은 설치 결과를 담는다. 프로젝트를 실행하기 위해 sudo pip install을 사용하거나, 환경 생성을 피하려고 externally managed system interpreter를 수정하지 않는다.
재현 가능한 프로젝트 예제
작은 애플리케이션도 pip freeze 결과를 설계 의도로 간주하기보다 직접 의존성과 build metadata를 pyproject.toml 등에 선언한다. 구체적인 형식은 선택한 build backend에 따라 달라진다. 저장소가 workflow를 정했다면 하나의 bootstrap 명령을 문서화하고 CI에서도 같은 방식을 사용한다.