Python Entwicklung
15. Feb. 2024
Python ist eine weit verbreitete und leicht zu erlernende Programmiersprache, die dank zahlreicher Erweiterungen (in Form von Modulen und Paketen) breit Anwendung findet. Doch da Python und dessen Erweiterungen ständig weiterentwickelt werden, kann es beim Teilen von Code zu Problemen kommen. Benutzt z.B. ein Kollege eine andere Version von Python oder einer installierten Erweiterung, so besteht die Möglichkeit, dass der Code, der auf dem eigenen Computer einwandfrei funktionert, beim Kollegen Fehler produziert. Arbeitet man zudem an unetrschiedlichen Projekten gleichzeitig, können sich verschiedene Erweiterungen gegenseitig stören, z.B. wenn Modul A für Projekt 1 ein Modul B mit Version 1.3 benötigt, bei Projekt 2 jedoch Modul B mit Version 2.1 zum Einsatz kommen soll. Werden alle Erweiterungen mit pip
installiert, kann dies die System-Version von Python "vollmüllen" und das Arbeiten an verschiedenen Projekten erschweren. Um diesem Problem Abhilfe zu verschaffen, bedient man sich einer Python Versionsverwaltung (mit pyenv
) und einer virtuellen Umgebung (mit virtualenv
). Wie diese Tools unter macOS installiert werden, wird in diesem Beitrag beschrieben.
Pyenv
Pyenv (Github) ist ein kleines Programm, das Python-Versionen verwaltet. Es wird entweder duch einen Script wie folgt installiert:
curl https://pyenv.run | bash
oder mittels Homebrew (meine bevorzugte Weise, Programme zu installieren) wie folgt:
brew update
brew install pyenv
Nach der Installation muss man noch den Shell-Start-Script aktualisieren, sodass Pyenv und die dafür benötigten Umgebungsvariablen geladen werden. Bei macOS wird zsh
als Shell eingesetzt, wesshalb die Datei .zshrc
im Benutzerordner (also ~/.zshrc
) wie folgt ergänzt werden muss:
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
Wie die Shell-Start-Scrips für andere Betriebssysteme und Shellumgebungen geändert werden müssen, wird im Github-Repository von Pyenv gut beschrieben.
Startet man das Terminal neu (oder läd die Änderungen mit source ~/.zshrc
), kann man den Befehl pyenv
eingeben und z.B. mit dem Argument --version
prüfen, ob die aktuellste Version von Pyenv richtig installiert wurde:
$ pyenv --version
pyenv 2.3.35
Um nun eine bestimmte Python-Version zu installieren, kann man sich mit dem folgenden Befehl, zuerst alle zur Verfügung stehenden Versionen auflisten lassen:
pyenv install --list
In meinem Fall waren es 743 verschiedene Versionen, die installiert werden können. Um z.B. Python 3.12.1 zu installieren, geht dies mit dem folgenden Befehl:
pyenv install 3.12.1
Nach erfolgreicher Installation lässt sich mit pyenv versions
prüfen, welche Versionen nun zur Auswahl stehen:
$ pyenv versions
* system
3.12.1
Man sieht, die neue Version ist installiert, aber prüft gibt man python --version
ins Terminal ein, sieht man, dass die System-Version benutzt wird. Dies kann geändert werden, mit den Befehlen pyenv local
und pyenv global
. Das Schlüsselwort local
weist Pyenv an, in dem derzeitigen Ordner eine bestimmte Python-Version zu benutzen, während global
eine Python-Version allgemein festsetzt.
Für Testzwecke können wir im Ordner ~/Developer/python-test
den folgenden Befehl ausführen:
pyenv local 3.12.1
und danach die Versionen abfragen:
$ pyenv versions
system
* 3.12.1 (set by /Users/maxi/Developer/python-test/.python-version)
Durch das Sternchen erkennt man, dass nun die zuletzt installierte Version von Python ausgewählt wurde. Dies liegt an der versteckten Datei .python-versions
im Ordner python-test
. Prüft man nun die Python-Version, sieht man, dass diese Version nun auch engesetzt wird:
$ python --version
Python 3.12.1
Der Folgende Befehl zeugt an, wo sich der Python-Interpreter befindet:
$ which python
/Users/maxi/.pyenv/shims/python
Man sieht, dass Python in einem von Pyenv erstellten Ordner gespechert ist. Werden nun mehrere Versionen von Python wie oben installiert, speichert Pyenv alle Versionen in diesem Ordner und durch Angabe einer Version mittel local
oder global
wird auf die entsprechende Version verwiesen.
Das bedeute aber auch, dass zwei Projekten die dieselbe Python-Version bebutzen, auch dieselben Erweiterungen (also Module und Pakete) bereitgestellt werden. Installiert man eine Erweiterung mittels pip
, so wird diese Erweiterung im Ordner .pyenv
im Benutzerordner (also ~/.pyenv
) für die derzeit ausgewählte Python-Version installiert und steht immer dann zur Verfügung, wenn die entsprechende Python-Version eingesetzt wird.
Zwar kann man mit dem Schlüsselwort uninstall
die Python-Version entfernen und sie mit install
sauber neu installieren. Doch das ist umständlich, wenn zwischen verschiedenen Projekten gewechselt und dafür Python immer erneut installiert werden muss. So kommen wir zum zweiten Tool: virtualenv
Virtualenv
Eine virtuelle Umgebung, die mit virtualenv
erstellt wird, kann man sich wie eine lokale Kopie der derzeit verwendeten Python-Version vorstellen, die alle Erweiterungen lokal verwaltet und somit die ursprüngliche Python-Installation unverändert lässt. Das Modul muss zuerst installiert werden (und zwar für jede frisch installierte Python-Version) mit dem folgenden Befehl:
pip install virtualenv
Und nun kann man z.B. im Ordner ~/Developer/python-test
eine virtuelle Umgebung wie folgt anlegen:
python -m virtualenv .venv
Dadurch wird ein versteckter Ordner namens .venv
erzeugt, der die derzeit aktivierte Python-Version lokal bereitstellt. Aktiviert man diese virtuelle Umgebung mit:
source .venv/bin/activate
so kann man nun mithilfe von pip
Erweiterungen lokal installieren, also ohne dass die ursprüngliche Python-Version im .pyenv
Ordner oder denn die System-Version, verändert (oder "vollgemüllt") wird. Alle Erweiterungen werden ausschließlich im .venv
Ordner lokal installiert.
Möchte man die virtuelle Umgebung verlassen, so wird sie wie folgt deaktiviert:
deactivate
Man kann den .venv
Ordner ohne Bedenken löschen und neu erstellen und ist somit von Projekt zu Projekt flexibel hinsichtlich der Installation verschiedener Erweiterungen.
Letzter Tipp
Hat man mehrere Erweiterungen in einer virtuellen Umgebung installiert und möchte seinen Code teilen, so empfiehlt sich die folgende Herangehensweise. Mit dem folgenden Befehl werden alle Module und Pakete in einer Datei so angeben:
pip freeze > requirements.txt
dass ein Kollege (nachdem er die virtuelle Umgebung mit der entsprechenden Python-Version aufgesetzt und aktiviert hat) alle Abhängigkeiten schnell installieren und den Code ausführen kann:
pip install -r requirements.txt
Das bedeutet, man muss nicht den .venv
Ordner mit allen Erweiterungen teilen (insb. nicht auf Github). Stattdessen braucht nur nur angeben, welche Python-Version einzusetzen ist (z.B. in der Readme.md
Datei oder durch die .python-version
Datei) und man muss die Abhängigkeiten durch die requirements.txt
Datei angeben. Somit ist alles bereitgestellt, um den Code ausführen zu können.