Zainstaluj na jednym komputerze dwa projekty w Pythonie i drugi może zepsuć pierwszy. Jeden potrzebuje requests==2.28, drugi requests==2.32, a pip ma dokładnie jeden systemowy katalog site-packages, do którego zapisuje. Wygrywa ostatnia instalacja, po cichu. Zauważasz to, gdy drugi projekt zaczyna zgłaszać błędy, które nie mają nic wspólnego z kodem, który właśnie zmieniłeś.
Wirtualne środowisko daje każdemu projektowi własny site-packages. Nic globalnego się nie zmienia, a dwa projekty mogą zależeć od niekompatybilnych wersji tej samej biblioteki, bez wzajemnej kolizji.
Co to jest wirtualne środowisko Python?
venv to katalog z trzema elementami: interpreterem Pythona (na Linuksie i macOS symlink do systemowego), plikiem pyvenv.cfg, który wskazuje tę bazową instalację, oraz folderem site-packages, do którego pip install zapisuje pakiety. Aktywacja ustawia katalog bin venv (Scripts na Windows) na początku PATH w twojej powłoce, więc python i pip wskazują na kopie z venv, a nie systemowe.
To cały mechanizm. Nie ma izolacji systemu plików ani drugiej kopii Pythona. venv zmienia tylko to, gdzie powłoka znajduje dwa pliki wykonywalne i skąd rozwiązywane są importy — dlatego stworzenie go trwa sekundę, a usunięcie to rm -rf .venv. Jeśli potrzebujesz izolować też system operacyjny i system plików, to zadanie dla kontenera, nie dla venv.
Jak stworzyć i aktywować venv?
Biblioteka standardowa zawiera moduł venv, więc nie trzeba niczego instalować:
| |
.venv to konwencjonalna nazwa, której domyślnie szukają uv i większość edytorów. Aktywacja zależy od powłoki:
| System / shell | Komenda |
|---|---|
| Linux / macOS (bash, zsh) | source .venv/bin/activate |
| Windows (cmd.exe) | .venv\Scripts\activate.bat |
| Windows (PowerShell) | .venv\Scripts\Activate.ps1 |
Świeża instalacja Windows blokuje skrypty PowerShell, w tym skrypt aktywacyjny. Zezwól na lokalnie utworzone skrypty, raz na użytkownika:
| |
Po aktywacji venv prompt zyskuje prefiks (.venv), a which python (where python na Windows) wskazuje plik w .venv. Uruchom deactivate, żeby wrócić. To funkcja powłoki zdefiniowana przez skrypt aktywacyjny, nie osobny program.
Aktywacja jest opcjonalna. .venv/bin/python script.py i .venv/bin/pip install requests działają bez niej, i tak właśnie pipeline’y CI i edytory wywołują venv pod maską.
Gdy masz zainstalowanych kilka wersji Pythona, python -m venv używa tego python, który powłoka znajdzie pierwszy, a to często nie ta wersja, o którą chodziło. Podaj wersję wprost: python3.12 -m venv .venv na Linuksie i macOS. Na Windows użyj launchera py dostarczanego z Pythonem, który wybiera wersję po numerze niezależnie od PATH: py -3.12 -m venv .venv.
Jak instalować pakiety za pomocą pip i requirements.txt?
W aktywnym venv pip install <package> robi to, czego oczekujesz. Dla powtarzalności liczy się zapisanie tego, co zostało zainstalowane:
| |
pip freeze zapisuje każdy zainstalowany pakiet z jego dokładną wersją, wliczając zależności twoich zależności. Zrób commit requirements.txt, a każdy, kto klonuje projekt, uruchamia:
| |
i dostaje te same wersje, które miałeś. Słaby punkt: plik miesza to, o co prosiłeś, z wszystkim, co pip przyniósł po drodze. Sześć miesięcy później odróżnienie “potrzebuję Flaska” od “Flask potrzebował Werkzeuga 3.1.3” oznacza przeczytanie całej listy i zgadywanie.
pyproject.toml czy requirements.txt: jaka jest różnica?
pyproject.toml zapisuje tylko twoje bezpośrednie zależności, z zakresami wersji:
| |
pip install . czyta ten plik i rozwiązuje całe drzewo zależności w momencie instalacji. pip install ".[dev]" dodaje do tego grupę dev. Ten sam plik przechowuje metadane pakowania, jeśli kiedyś opublikujesz projekt — coś, do czego requirements.txt nigdy nie był przeznaczony.
Czego nie robi: nie przypina konkretnych wersji. flask>=3.0 rozwiązuje się do najnowszej wersji dostępnej w dniu instalacji. Przypinanie to zadanie dla lock file, a venv + pip go nie dają.
W buildzie kontenera to plik, który kopiujesz przed resztą kodu źródłowego, żeby warstwa zależności przebudowywała się tylko wtedy, gdy zmienia się pyproject.toml. Przewodnik po dobrych praktykach Dockerfile wyjaśnia, czemu ta kolejność ma znaczenie dla cache builda.
Jak używać uv zamiast venv i pip?
uv to jeden binarny plik w Rust, który obejmuje zadania venv, pip, pip-tools i pyenv: uv python install 3.12 pobiera i zarządza wersjami Pythona tak jak pyenv, więc uv venv --python 3.12 działa, nawet jeśli tej wersji jeszcze nie ma na komputerze. Jest też na tyle szybki, że to widać: rozwiązanie zależności, które pipowi zajmuje kilka sekund, kończy się w ułamku tego czasu.
Zainstaluj go raz (dokumentacja astral.sh ma komendę dla każdej platformy). Potem możesz go używać w dwóch trybach.
Jako bezpośredni zamiennik venv i pip, jeśli chcesz tylko szybkości:
| |
uv venv tworzy .venv tak samo jak python -m venv .venv, a uv pip install przyjmuje te same argumenty co pip. Wynik aktywujesz jak każdy inny venv.
W trybie projektu, który dodaje locking:
| |
uv init tworzy szkielet pyproject.toml. uv add zapisuje w nim zależność, rozwiązuje całe drzewo i zapisuje plik uv.lock, który przypina każdą rozwiązaną wersję, włącznie z przechodnimi, razem z hashami. Ten lock file to element, którego pip nie produkuje. Zrób commit pyproject.toml i uv.lock, a kolega z zespołu uruchamia:
| |
To tworzy .venv, jeśli go nie ma, i instaluje dokładnie to, co mówi lock file, a nie to, co zakresy wersji w pyproject.toml rozwiążą tego dnia. uv run script.py wykonuje to samo sprawdzenie synchronizacji przed uruchomieniem, więc twoje środowisko nie może się rozjechać z lock file bez twojej wiedzy.
Jak naprawić najczęstsze błędy wirtualnych środowisk?
error: externally-managed-environment. Uruchomiłeś pip install poza venv na Debianie 12+, Ubuntu 23.04+, Fedorze 38+ lub podobnej dystrybucji, i systemowy Python odmówił. PEP 668 wprowadził plik znacznikowy, który menedżer pakietów systemu operacyjnego umieszcza w swojej instalacji Pythona, żeby powstrzymać pip przed nadpisywaniem pakietów, którymi zarządza też apt lub dnf. Wcześniej przypadkowe sudo pip install mogło zepsuć narzędzia samego systemu operacyjnego w sposób wyjątkowo trudny do debugowania. Niektóre starsze przewodniki mówią, żeby dodać --break-system-packages. Nie rób tego: to przywraca właśnie tę szkodę, przed którą chroni znacznik. Stwórz venv i instaluj tam.
Edytor uruchamia niewłaściwy interpreter. VS Code, PyCharm i podobne narzędzia używają tego, na co wskazywał python w momencie otwarcia projektu, a to nie musi być twój venv. Symptomy: importy, które działają w terminalu, pojawiają się w edytorze jako nierozwiązane, albo pakiet zainstalowany pięć minut temu nie jest znajdowany. Ustaw interpreter edytora wprost na .venv/bin/python (.venv\Scripts\python.exe na Windows).
venv trafił do gita. To kilkaset megabajtów plików binarnych plus absolutne ścieżki w pyvenv.cfg i skryptach aktywacyjnych, więc wszystko się psuje, gdy ktoś klonuje repozytorium do innej ścieżki lub na inny system. Dodaj .venv/ do .gitignore. Od Pythona 3.13 venv sam tworzy w nowym środowisku plik .gitignore, który ignoruje całą jego zawartość; na starszych wersjach musisz zrobić to sam. Zrób commit requirements.txt, albo pyproject.toml z uv.lock. Te pliki odbudowują środowisko wszędzie. Sam katalog nigdy nie powinien trafić do repozytorium.
venv, pyproject.toml czy uv: co wybrać?
Zostań przy venv + pip + requirements.txt dla małego projektu z krótką listą zależności, gdzie nie chcesz dodatkowego tooling. Przejdź na pyproject.toml, gdy pojawią się zależności potrzebne tylko w developmencie, takie jak test runnery i lintery, które nie powinny trafić na produkcję, albo gdy planujesz spakować projekt.
Dodaj uv, gdy szybkość rozwiązywania zależności zaczyna ci przeszkadzać albo chcesz mieć commitowany lock file bez ręcznego utrzymywania go za pomocą pip-tools. Nie wymusza żadnego przepisywania: uruchom uv init w nowym projekcie, albo uv venv i uv pip install -r requirements.txt w istniejącym, i przejdź na uv add, gdy będziesz gotowy na lock file.