Zurück zur Startseite

venv-Architektur in Python: Wie pyvenv.cfg sys.path verwaltet

Der Artikel erklärt, wie virtuelle Umgebungen in Python Abhängigkeitsisolation auf CPython-Ebene durch die pyvenv.cfg-Datei und Neuberechnung von sys.path bieten. Er behandelt Low-Level-Architektur, minimale Umgebungsanforderungen und Diagnosemethoden.

Wie CPython pyvenv.cfg liest und Abhängigkeiten isoliert
Advertisement 728x90

Wie CPython die Isolation virtueller Umgebungen implementiert: Architektur, pyvenv.cfg und Low-Level-Logik von sys.path

Virtuelle Umgebungen in Python sind kein abstraktes Konzept – sie sind ein klar definiertes System, das die Interaktionen zwischen dem Dateisystem, Konfigurationsdateien und dem C-Code des Interpreters orchestriert. Ihre Isolation wird nicht durch Containerisierung oder Importabfangung erreicht; stattdessen beruht sie auf deterministischen Änderungen am Verhalten des Modulladers während der Initialisierung. Dies ist entscheidend für reproduzierbare Builds, CI/CD-Pipelines und Multi-Projekt-Entwicklungsumgebungen.

Warum virtualenv veraltet ist, während venv ohne pip funktioniert

Vor Python 3.3 wurde die Isolation von Umgebungen extern gehandhabt: virtualenv kopierte das Interpreter-Binary, duplizierte die Standardbibliothek und patchte sys.path über Wrapper. Dies verlangsamte die Erstellung von Umgebungen, verbrauchte mehr Speicherplatz und erschwerte das Debugging. Mit der Einführung von PEP 405 wurde dieser Mechanismus in den Kern von CPython integriert. Der Hauptunterschied besteht darin, auf das Kopieren von Binärdateien zu verzichten und stattdessen symbolische Links (Linux/macOS) oder Launcher (Windows) zu verwenden, wodurch venv sofort verfügbar ist und nur von der installierten Python-Version abhängt.

Die wichtigste technische Verschiebung besteht darin, die Logik von externen Tools in den Interpreter selbst zu verlagern. Anstatt Python über Umgebungsvariablen oder Shell-Wrappers „auszutricksen“, stützt sich venv auf einen internen Suchalgorithmus für pyvenv.cfg. Diese eine Datei ist der Auslöser, der CPython dazu zwingt, sys.path neu aufzubauen und globale site-packages zu deaktivieren.

Google AdInline article slot

Wie CPython pyvenv.cfg liest und sys.path neu berechnet

Die Initialisierung erfolgt auf C-Ebene beim Loader (Py_Initialize). Wenn das ausführbare Programm startet, folgt der Interpreter diesen Schritten:

  • Er ermittelt den Speicherort des Executables (z. B. /project/.venv/bin/python).
  • Er wandert im Verzeichnisbaum nach oben, bis er pyvenv.cfg im übergeordneten Verzeichnis findet.
  • Er analysiert die Datei als INI-ähnliche Textdatei – mit CPythons Standardparser, ganz ohne externe Abhängigkeiten.
  • Wenn include-system-site-packages = false ist, werden globale Pfade vor dem Laden jeglichen Benutzer-Codes aus sys.path entfernt.
  • Er erstellt einen neuen sys.path: zuerst das aktuelle Skript, dann lib/pythonX.Y, anschließend die lokalen site-packages und erst nach expliziter Genehmigung – globale Pakete.

Das bedeutet, dass die Isolation auch gewährleistet ist, wenn man direkt .venv/bin/python -c "import sys; print(sys.path)" ausführt, ohne die Shell zu aktivieren. Die Aktivierung (source .venv/bin/activate) beeinflusst lediglich $PATH und VIRTUAL_ENV, nicht jedoch das Verhalten des Interpreters.

Implementierung eines minimalen venv: Was wirklich notwendig ist

Um eine funktionierende virtuelle Umgebung zu erstellen, braucht es genau drei Komponenten – und nichts weiter. Weder pip, noch setuptools, noch die Shell spielen bei der grundlegenden Isolation eine Rolle.

Google AdInline article slot
  • Verzeichnisstruktur: bin/, lib/pythonX.Y/site-packages/
  • Datei pyvenv.cfg: enthält home, include-system-site-packages, version, executable
  • Ausführbares in bin/: ein Symlink (Unix) oder Launcher (Windows), der auf den System-Python zeigt

Alles andere sind Komfortfunktionen: pip, activate, pyproject.toml. Hier ist ein minimales Arbeitsbeispiel für Linux:

#!/bin/bash
ENV_DIR="my_venv"
mkdir -p "$ENV_DIR/bin" "$ENV_DIR/lib/python$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')/site-packages"

cat > "$ENV_DIR/pyvenv.cfg" <<EOF
home = $(dirname $(which python))
include-system-site-packages = false
version = $(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))')
executable = $(which python)
EOF

ln -sf "$(which python)" "$ENV_DIR/bin/python"

Wenn man ./my_venv/bin/python -c "import sys; print([p for p in sys.path if 'site-packages' in p])" ausführt, zeigt dies nur den lokalen Pfad – ohne Einbeziehung dritter Tools.

Wichtige Erkenntnisse

  • Die Isolation virtueller Umgebungen ist ein Zustand von CPython, nicht von Prozess oder Shell. Sie tritt in Kraft, wenn der Interpreter startet, nicht wenn die Umgebung aktiviert wird.
  • Die Datei pyvenv.cfg ist das einzige obligatorische Artefakt. Entfernt man sie, wird die Umgebung zu einem normalen Verzeichnis mit einem Symlink.
  • sys.path wird vor dem Ausführen jeglichen Python-Codes neu aufgebaut, einschließlich site.py. Globale Pakete sind physisch unzugänglich.
  • Poetry, Pipenv und andere Dependency-Manager bauen auf venv auf. Sie ändern die Isolationslogik nicht; sie automatisieren lediglich das Erstellen von pyvenv.cfg und das Management von site-packages.
  • Symbolische Links sind sicher: CPython entpackt sie korrekt und verwendet den tatsächlichen home, der in pyvenv.cfg angegeben ist, statt des Pfads des Symlinks.

Debugging und Diagnose der Isolation

Wenn eine Umgebung sich unerwartet verhält, sollte man nicht pip list prüfen, sondern direkt den Zustand des Interpreters untersuchen:

Google AdInline article slot
  • Stellen Sie sicher, dass pyvenv.cfg existiert und include-system-site-packages = false setzt.
  • Führen Sie .venv/bin/python -c "import sys; print(sys.prefix, sys.base_prefix, sys.path)" aus – vergleichen Sie prefix und base_prefix.
  • Überprüfen Sie, ob sys.path genau einen einzigen site-packages-Eintrag enthält – den lokalen.
  • Führen Sie .venv/bin/python -c "import site; print(site.getsitepackages())" aus – es sollte eine Liste mit einem einzigen Element zurückgeben.

Wenn globale Pakete weiterhin sichtbar sind, bedeutet das, dass pyvenv.cfg fehlt, beschädigt ist oder include-system-site-packages auf true gesetzt wurde. Keine Umgebungsvariablen (PYTHONPATH, PYTHONHOME) können dieses Verhalten außer Kraft setzen – es ist fest in CPython eingebettet.

— Editorial Team

Advertisement 728x90

Weiterlesen