파이썬(virtual env) 가상환경 만들기, venv와 uv로 직접 해 보니
파이썬 virtual env를 venv와 uv로 만들고, 켜고, 끄고, 지워 봤습니다. 맥 한 대에서 한 번 실행한 결과 venv는 1.1초, uv는 0.1초 걸렸습니다. 켜기 전후에 실행되는 파이썬 위치가 어떻게 바뀌는지, 가상환경인지 확인하는 방법까지 함께 정리했습니다.
Finn ·

맥 한 대에서 python3 -m venv .venv로 파이썬 가상환경을 만드는 데는 1.1초, uv venv로 만드는 데는 0.1초가 걸렸습니다. 켜기 전에 /opt/homebrew/bin/python3를 가리키던 명령은 켠 뒤 ./.venv/bin/python으로 바뀌었고, 끄자 원래대로 돌아왔죠. virtual env를 처음 만들거나, AI 코딩 도구가 패키지를 어디에 설치하는지 헷갈렸다면 아래 8단계를 그대로 따라 해 보세요.
따라 할 순서 한눈에 보기
- 쓸 파이썬 버전을 확인합니다.
- 프로젝트 폴더에
.venv가상환경을 만들고pyvenv.cfg를 열어 봅니다. - 가상환경을 켜고, 켜기 전후의
python위치와VIRTUAL_ENV값을 비교합니다. - 가상환경 안의
pip과 설치된 패키지 목록을 확인합니다. - 지금 실행 중인 파이썬이 가상환경인지 코드로 확인합니다.
deactivate로 끄고 원래 파이썬으로 돌아왔는지 봅니다.- 같은 일을
uv venv로 해 봅니다. - 다 쓴 가상환경은 폴더째 지웁니다.

단계로 들어가기 전에, 가상환경을 왜 따로 만드는지부터 짧게 짚고 넘어가겠습니다.
함께 읽을 글
파이썬 가상환경은 왜 쓰나요?
Python 공식 문서 venv에 따르면 가상환경은 이미 설치된 파이썬(기본 파이썬, base) 위에 만들어집니다. 기본적으로 그 기본 환경의 패키지와는 분리돼서, 가상환경에 직접 설치한 패키지만 보이죠. 그래서 가상환경 안에서 pip을 쓰면 따로 지정하지 않아도 패키지가 가상환경에 설치됩니다.
문서가 꼽는 성질은 AI 에이전트에게 작업을 맡길 때 그대로 규칙으로 쓸 수 있습니다.
- 보통 프로젝트 폴더 안의
.venv나venv라는 폴더에 둡니다. - Git 같은 버전 관리 시스템에 올리지 않습니다.
- 언제든 지우고 처음부터 다시 만드는 일회용으로 보고, 프로젝트 코드는 그 안에 두지 않습니다.
- 다른 곳으로 옮기거나 복사하지 않고, 새 위치에서 다시 만듭니다.
그럼 도구는 무엇을 써야 할까요? venv는 파이썬 3.3부터 표준 라이브러리에 들어 있고, 3.5부터는 가상환경을 만들 때 venv를 쓰도록 권합니다. 예전 도구인 pyvenv는 3.6에서 폐기 예고된 뒤 3.8에서 제거됐어요.
uv 문서는 파이썬 설치 자체의 환경을 고치지 않는 것을 모범 사례로 꼽습니다. 그리고 pip과 달리 uv는 기본적으로 가상환경을 쓰도록 요구한다고 설명하죠. virtualenv는 이 글의 근거 문서가 따로 다루지 않아서 여기서는 비교하지 않습니다.
가상환경 만드는 방법
먼저 어떤 파이썬 위에 만들지 확인합니다. 이번 측정에서는 Homebrew로 설치된 python3가 3.15.0이었습니다.
$ python3 --version
Python 3.15.0이제 현재 폴더에 .venv를 만들고, 생긴 파일과 설정 파일을 바로 열어 봅니다. 이 단계에 1.1초가 걸렸습니다.
$ python3 -m venv .venv && ls .venv && cat .venv/pyvenv.cfg
bin
include
lib
pyvenv.cfg
home = /opt/homebrew/opt/python@3.15/bin
include-system-site-packages = false
version = 3.15.0
executable = /opt/homebrew/Cellar/python@3.15/3.15.0_1/Frameworks/Python.framework/Versions/3.15/bin/python3.15
command = /opt/homebrew/opt/python@3.15/bin/python3.15 -m venv ./.venv문서 설명대로 bin에는 파이썬 실행 파일의 복사본이나 심볼릭 링크가, lib 아래에는 패키지가 들어갈 site-packages가 생깁니다. pyvenv.cfg의 home은 명령을 실행한 파이썬 설치 위치를 가리키죠. include-system-site-packages는 --system-site-packages 옵션 없이 만들었기 때문에 false이고, 시스템 쪽 패키지에는 접근하지 않는다는 뜻입니다.
참고로 파이썬 3.13부터 venv는 Git용 .gitignore 파일도 기본으로 만들어 줍니다. 위 ls 출력에는 나오지 않았으니, 직접 확인하려면 숨김 파일까지 보이게 목록을 띄워 보세요.
가상환경을 켜면 무엇이 바뀌나요?
켜기 전과 켠 뒤에 python이 어디를 가리키는지 한 줄로 비교해 봤습니다.
$ echo "켜기 전: $(which python3)" && source .venv/bin/activate && echo "켠 뒤: $(which python)" && python --version && echo "VIRTUAL_ENV=$VIRTUAL_ENV"
켜기 전: /opt/homebrew/bin/python3
켠 뒤: ./.venv/bin/python
Python 3.15.0
VIRTUAL_ENV=./.venv켜는 순간 python이 .venv 안의 실행 파일로 바뀌고, VIRTUAL_ENV에는 가상환경 경로가 들어갔습니다. 문서에 따르면 켜기는 가상환경의 bin 폴더를 PATH 맨 앞에 붙이는 일입니다. 그래서 python만 입력해도 가상환경의 인터프리터가 실행되는 거예요.

그런데 주의할 점이 있습니다. 이 측정은 단계마다 새 셸에서 실행해서, 켠 상태가 다음 단계로 이어지지 않았어요. 그래서 4·5단계는 .venv/bin/pip, .venv/bin/python처럼 전체 경로로 불렀습니다.
평소처럼 터미널 창 하나에서 작업한다면 사정이 다릅니다. 켜기는 그 셸의 PATH를 바꾸는 일이라서, 같은 창에서 deactivate로 끌 때까지 유지되죠. 셸별로 켜는 명령은 문서에 이렇게 정리돼 있습니다.
| 플랫폼 | 셸 | 켜는 명령 |
|---|---|---|
| POSIX | bash/zsh | source <venv>/bin/activate |
| POSIX | fish | source <venv>/bin/activate.fish |
| POSIX | csh/tcsh | source <venv>/bin/activate.csh |
| 윈도우 | cmd.exe | <venv>\Scripts\activate.bat |
| 윈도우 | PowerShell | <venv>\Scripts\Activate.ps1 |
AI 코딩 도구가 명령마다 새 셸을 띄우는 방식이라면, 켠 상태가 이어진다고 가정하지 않는 편이 좋습니다. 문서도 켜지 않고 그 환경 파이썬의 전체 경로만 지정해도 된다고 설명하니, 에이전트에게 .venv/bin/python처럼 경로를 적어 부르도록 지시해 보세요.
가상환경 안에는 무엇이 설치돼 있나요?
막 만든 가상환경에 무엇이 들어 있는지 볼 차례입니다. 이 단계는 0.5초 걸렸습니다.
$ .venv/bin/pip --version && .venv/bin/pip list --disable-pip-version-check
pip 26.2.2 from ./.venv/lib/python3.15/site-packages/pip (python 3.15)
Package Version
------- -------
pip 26.2.2pip은 가상환경 안의 site-packages에서 실행됐고, 패키지는 pip 하나뿐이었습니다. 문서에 따르면 --without-pip 옵션을 주지 않는 한 venv가 ensurepip로 pip을 넣어 줍니다. 그러니 에이전트가 코드를 돌리다 모듈을 못 찾는다고 하면, 먼저 이 목록에 그 패키지가 있는지부터 확인하는 편이 빠릅니다.
지금 가상환경인지 코드로 확인하는 법
그렇다면 실행 중인 코드가 가상환경 안에서 도는지는 어떻게 알 수 있을까요? 문서는 sys.prefix와 sys.base_prefix가 다른지만 보면 충분하다고 말합니다.
$ .venv/bin/python -c 'import sys; print(sys.prefix); print(sys.base_prefix); print("가상환경:", sys.prefix != sys.base_prefix)'
./.venv
/opt/homebrew/opt/python@3.15/Frameworks/Python.framework/Versions/3.15
가상환경: Truesys.prefix는 가상환경 폴더를, sys.base_prefix는 가상환경을 만든 기본 파이썬을 가리켰습니다. 반대로 VIRTUAL_ENV 값으로는 판단할 수 없다고 문서는 분명히 적고 있어요. 켜지 않고 전체 경로로 실행해도 가상환경은 쓰이기 때문이죠.

가상환경을 끄는 방법
끌 때는 같은 셸에서 deactivate를 입력합니다. 이번에도 새 셸이라 한 줄 안에서 켰다가 바로 껐습니다.
$ source .venv/bin/activate && deactivate && echo "끈 뒤: $(which python3)" && echo "VIRTUAL_ENV=${VIRTUAL_ENV:-없음}"
끈 뒤: /opt/homebrew/bin/python3
VIRTUAL_ENV=없음python3는 다시 Homebrew 쪽을 가리켰고, VIRTUAL_ENV는 비었습니다. 끄는 정확한 방식은 플랫폼마다 다른 내부 구현이라고 문서는 설명합니다.
uv로 만들 때 달라지는 점
이번에는 같은 일을 uv로 해 봤습니다. 캐시를 임시 폴더에 두려고 --cache-dir를 붙였고, 0.1초가 걸렸습니다.
$ uv venv uv-env --cache-dir ./uv-cache && uv-env/bin/python --version && ls uv-env/bin | head -8
Using CPython 3.12.14
Creating virtual environment at: uv-env
Activate with: source uv-env/bin/activate
Python 3.12.14
activate
activate.bat
activate.csh
activate.fish
activate.nu
activate.ps1
activate.xsh
activate_this.py눈여겨볼 점은 파이썬 버전입니다. venv는 3.15.0 위에 만들어졌지만, uv는 CPython 3.12.14를 골랐어요. 왜 이 버전을 골랐는지는 이 기록만으로는 알 수 없습니다. 버전을 정하고 싶다면 문서대로 직접 요청하면 됩니다. 요청한 버전이 시스템에 없으면 uv가 내려받습니다.
$ uv venv --python 3.11이름 없이 uv venv만 실행하면 .venv에 만들어지고, 이 기본 이름을 쓰면 이후 명령이 알아서 그 가상환경을 찾아 씁니다.
$ uv venv
$ # Install a package in the new virtual environment
$ uv pip install ruffuv가 가상환경을 찾는 순서는 이렇습니다. 에이전트가 엉뚱한 곳에 패키지를 설치했다면 이 순서부터 따져 보세요.
VIRTUAL_ENV환경 변수로 켜진 가상환경CONDA_PREFIX로 켜진 Conda 환경- 현재 폴더 또는 가장 가까운 상위 폴더의
.venv
그렇다면 uv가 venv보다 빠르다고 봐도 될까요? 이번 결과는 1.1초와 0.1초지만 한 번씩만 실행했고, 쓴 파이썬 버전도 달랐습니다. 이 측정만으로는 원인을 가를 수 없으니, 같은 파이썬 버전을 지정해 여러 번 돌려 보며 직접 비교해 보세요.
가상환경 지우는 방법
다 쓴 가상환경은 폴더를 지우면 끝입니다. 캐시 폴더까지 함께 지우는 데 0.1초가 걸렸고, 폴더에는 아무것도 남지 않았습니다.
$ rm -rf .venv uv-env uv-cache && ls -a
.
..문서는 가상환경을 옮길 수 없는 것으로 봅니다. 설치된 스크립트의 첫 줄(shebang)에 그 환경 인터프리터의 절대 경로가 들어가기 때문이죠. 그래서 상위 폴더를 옮겼다면 새 위치에서 다시 만들어야 합니다. 쉽게 다시 만들 수 있도록 requirements.txt를 두고, 그 환경의 pip으로 pip install -r requirements.txt를 실행하면 됩니다.
자주 하는 실수
- 켠 상태가 다음 명령에도 이어진다고 가정합니다. 명령마다 새 셸이 뜨면 켜기는 이어지지 않습니다. 이럴 때는
.venv/bin/python처럼 전체 경로로 부르세요. VIRTUAL_ENV로 가상환경 여부를 판단합니다. 문서는sys.prefix != sys.base_prefix를 보라고 합니다.- 가상환경 폴더를 옮기거나 복사합니다. 옮긴 곳에서 다시 만드는 것이 문서가 권하는 방법입니다.
- 가상환경을 Git에 올립니다. 버전 관리에 넣지 않는 것이 원칙입니다.
- 윈도우 PowerShell에서
Activate.ps1이 막힙니다. 문서는 현재 사용자의 실행 정책을 이렇게 바꾸라고 안내합니다.
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser커밋 전에 확인할 것
- 가상환경 폴더 이름이
.venv또는venv인가요? - 가상환경 폴더가 Git 추적 대상에서 빠져 있나요?
requirements.txt처럼 가상환경을 다시 만들 수단이 있나요?- 코드에서
sys.prefix와sys.base_prefix가 서로 다르게 나오나요? - uv를 쓴다면 의도한 파이썬 버전으로 만들어졌나요?
측정 조건과 한계
측정은 2026-10-27에 맥 한 대(darwin arm64)에서 했습니다. 새 임시 폴더에서 명령을 적힌 순서대로 한 번씩 실행했고, 이 컴퓨터에 Homebrew로 설치돼 있던 python3와 uv를 썼습니다. 단계마다 새 셸에서 실행했고, 모든 단계의 종료 코드는 0이었습니다.
| 단계 | 걸린 시간 |
|---|---|
| 1. 파이썬 버전 | 0.0초 |
| 2. 가상환경 만들기 | 1.1초 |
| 3. 켜기 전과 켠 뒤 | 0.0초 |
| 4. 가상환경 안의 pip | 0.5초 |
| 5. 가상환경인지 코드로 보기 | 0.0초 |
| 6. 끄기 | 0.0초 |
| 7. uv로 만들기 | 0.1초 |
| 8. 지우기 | 0.1초 |

한 번만 실행한 값이라 실행할 때마다 달라질 수 있고, venv와 uv는 서로 다른 파이썬 버전(3.15.0과 3.12.14)으로 만들어졌습니다. 따라서 이 표는 두 도구의 속도를 가르는 기준보다는, 각 단계가 무엇을 출력하는지 확인하는 기록으로 읽어 주세요.
참고 자료
- venv — 가상 환경 생성 docs.python.org
- Using Python environments docs.astral.sh