TATECHATLAS
◎ Deutsch
Programmierung / Anleitung

Umgang mit Umgebungsvariablen in Python: os.environ, os.environb und plattformübergreifende Aspekte

Wie man Umgebungsvariablen in Python mit os.environ und os.environb liest, ändert und synchronisiert, Kodierungsunterschiede über Plattformen hinweg behandelt und Umgebungen an Kindprozesse übergibt.

Auf dieser Seite

os.environ ist ein dictionaryähnlicher Schnappschuss der Prozessumgebung, der beim Start des Interpreters erfasst wird. Änderungen daran rufen automatisch setenv oder unsetenv auf, aber os.putenv aktualisiert die Zuordnung nicht. Unter Unix bietet os.environb eine Bytes-Ansicht, die mit os.environ synchronisiert ist. Die Kodierung von Schlüsseln und Werten hängt von der Dateisystemkodierung oder dem UTF-8-Modus ab. os.reload_environ (Python 3.14+) aktualisiert den Cache nach externen Änderungen, ist jedoch nicht threadsicher. Kindprozesse erhalten die Umgebung über den env-Parameter der spawn*- und exec*-Funktionen, der String-Schlüssel und -Werte enthalten muss.

Lesen von Umgebungsvariablen über os.environ und os.getenv

os.environ ist ein Mapping-Objekt, das die Prozessumgebung darstellt. Der Zugriff auf einen Schlüssel, der nicht existiert, wirft einen KeyError aus, während os.environ.get(key, default) das Standardergebnis zurückgibt. os.getenv(key, default=None) ist eine Hilfsfunktion, die ebenfalls None zurückgibt, wenn die Variable fehlt. Der kritische Unterschied liegt zwischen einer nicht gesetzten Variable (gibt None zurück) und einer auf einen leeren String gesetzten Variable (gibt '' zurück). Die Verwendung der Wahrheitswertigkeit des Ergebnisses vermischt diese beiden Zustände, was Konfigurationsfehler in Produktionsbereitstellungen stillschweigend maskieren kann.

Die Quelldokumentation besagt, dass environ ein Mapping ist, bei dem sowohl Schlüssel als auch Werte Strings sind. Auf Plattformen, die den Zugriff auf Bytes-Umgebungen unterstützen, steht die Bytes-Darstellung über os.environb und os.getenvb zur Verfügung. Für den meisten Anwendungscode reicht os.environ oder os.getenv aus, da der Interpreter das Decodieren aus der Dateisystemkodierung oder dem UTF-8-Modus automatisch handhabt.

import os

# Distinguish absent from empty
value = os.environ.get("APP_MODE")
if value is None:
    print("variable not set")
else:
    print("value:", repr(value))

Wenn Sie feststellen müssen, ob eine Variable wirklich fehlt oder auf einen leeren String gesetzt ist, verwenden Sie os.environ.get(name) und prüfen Sie auf None, statt sich auf die Wahrheitswertigkeit zu verlassen, da ein leerer String falsch ist, aber semantisch anders als eine nicht gesetzte Variable.

Ändern und Löschen von Variablen über os.environ

Das Zuweisen zu os.environ[key] ruft die zugrunde liegende setenv-Systemfunktion auf. Das Löschen eines Schlüssels ruft unsetenv auf. Die Methoden pop() und clear() lösen ebenfalls unsetenv für jeden entfernten Eintrag aus. Diese automatische Synchronisation ist der Grund, warum die Dokumentation empfiehlt, os.environ zu ändern, anstatt direkt os.putenv aufzurufen, weil putenv in das C-Level-environ-Array schreibt, ohne die Python-Zuordnung zu aktualisieren, wodurch os.environ veraltet bleibt.

Auf einigen Plattformen, einschließlich FreeBSD und macOS, können wiederholte Aufrufe von setenv oder putenv zu Speicherlecks im C-Laufzeitbereich führen. Dies ist ein plattformbedingtes Problem und kein Python-Bug, bedeutet aber, dass langlebige Prozesse, die häufig Umgebungsvariablen ändern, die Anzahl der erstellten distincten Schlüssel minimieren sollten.

import os

os.environ["APP_MODE"] = "production"  # calls setenv
os.environ.pop("APP_MODE", None)       # calls unsetenv if present

Synchronisation von os.environ und os.environb

os.environb ist eine Bytes-Version des Mappings, die nur verfügbar ist, wenn os.supports_bytes_environ True ist, was auf Unix-Plattformen zutrifft. Die beiden Abbildungen werden synchron gehalten: Änderungen an environb aktualisieren environ und umgekehrt. Das bedeutet, Sie können einen Bytes-Wert an environb schreiben und den decodierten String aus environ lesen oder umgekehrt. Unter Windows ist supports_bytes_environ False und environb existiert nicht, sodass Code, der beide Plattformen unterstützt, den Zugriff mit diesem Flag schützen muss.

Die Synchronisation verwendet die Dateisystemkodierung und ihren Fehlerhandler für die Konvertierung zwischen Bytes und str. Wenn ein Bytes-Wert Sequenzen enthält, die unter der aktuellen Kodierung nicht decodiert werden können, erzeugt surrogateescape einzelne Surrogates in der str-Ansicht. Das Hin- und Herlaufen durch beide Darstellungen bewahrt die ursprünglichen Bytes.

import os

if os.supports_bytes_environ:
    os.environb[b"RAW_KEY"] = b"\xff\xfe"
    print(os.environ["RAW_KEY"])  # decoded via fsencode/fsdecode

Kodierungen: UTF-8-Modus, fsencode/fsdecode und getenvb

Wenn der Python UTF-8-Modus aktiv ist (aktiviert über -X utf8 oder PYTHONUTF8=1 oder automatisch, wenn die Lokalisierung C oder POSIX ist), werden Umgebungsvariablen unabhängig vom Systemlokalität mit UTF-8 decodiert. Außerhalb des UTF-8-Modus regelt die Dateisystemkodierung das Decodieren. os.fsencode und os.fsdecode stellen diese Konvertierungen explizit bereit und sind der empfohlene Weg, um pfadähnliche Bytes zu behandeln, die in Umgebungsvariablenwerten auftreten können.

os.getenvb gibt die rohen Bytes einer Umgebungsvariable ohne jeden Decodierschritt zurück. Dies ist nützlich, wenn Sie Werte untersuchen oder weiterleiten müssen, die Bytes enthalten könnten, die unter der aktuellen Kodierung ungültig sind, oder wenn Sie portablen Code schreiben, der den impliziten Decodier-dann-Rekodier-Rundlauf vermeiden muss.

import os, sys

print("filesystem encoding:", sys.getfilesystemencoding())
print("utf8 mode:", sys.flags.utf8_mode)

# Raw bytes access (Unix only)
if os.supports_bytes_environ:
    raw = os.getenvb(b"LANG")
    print("LANG bytes:", raw)

Umgebungscache und os.reload_environ

Die Dokumentation ist ausdrücklich: os.environ und os.environb sind ein Cache von Umgebungsvariablen zum Zeitpunkt des Starts von Python. Änderungen, die außerhalb des Interpreters vorgenommen werden oder durch os.putenv und os.unsetenv erfolgen, werden in der Zuordnung nicht widergespiegelt. os.reload_environ, das in Python 3.14 hinzugefügt wurde, aktualisiert beide Abbildungen aus der aktuellen Prozessumgebung. Vor 3.14 gab es keinen Standardmechanismus, um den Cache nach externer Modifikation neu zu synchronisieren.

Dies ist wichtig in Szenarien, in denen ein Elternprozess oder ein Signalhandler die Umgebung über C-Level-APIs ändert oder wenn eine Bibliothek putenv aufruft, ohne os.environ zu verwenden. Ohne reload_environ geben nachfolgende Lesevorgänge veraltete Werte zurück.

import os

# After external modification of the process environment:
os.reload_environ()  # Python 3.14+
print(os.environ.get("EXTERNALLY_SET_VAR"))

Fehler und Threadsicherheit bei der Arbeit mit der Umgebung

Alle Funktionen im os-Modul werfen OSError oder eine Unterklasse aus, wenn Argumente korrekte Typen haben, aber vom Betriebssystem abgelehnt werden. Bei Umgebungsoperationen ist dies selten, da setenv und unsetenv für gültige Strings erfolgreich sind, aber ungültige Surrogatzeichen in Schlüsseln oder Werten UnicodeEncodeError auslösen können, bevor der Systemaufruf erreicht wird.

os.reload_environ trägt eine ausdrückliche Warnung, dass es nicht threadsicher ist. Das Lesen von os.environ, os.environb oder das Aufrufen von os.getenv während eines Reloads kann ein leeres Ergebnis zurückgeben. In multithreaded Anwendungen sollte der Zugriff auf reload_environ serialisiert werden oder ganz vermieden werden, indem der Zustand der Umgebung ausschließlich durch os.environ-Mutationen verwaltet wird.

import os

try:
    os.environ["BAD_KEY"] = "value\ud800"  # lone surrogate
except UnicodeEncodeError as e:
    print("encoding error:", e)

Plattformübergreifende Portabilität: os.name, Plattformeinschränkungen und PATH

os.name gibt 'posix' auf Unix-ähnlichen Systemen und 'nt' unter Windows zurück. Auf WebAssembly, Android und iOS sind große Teile des os-Moduls nicht verfügbar oder verhalten sich anders: Prozess-APIs wie fork, execve und spawn fehlen, und getuid und getpid können Stubs sein. Code, der über diese Ziele hinweg laufen muss, sollte os.name und os.supports_bytes_environ prüfen, bevor er sich auf plattformspezifisches Verhalten verlässt.

os.get_exec_path gibt die Liste der Verzeichnisse zurück, die nach ausführbaren Programmen durchsucht werden, wobei die PATH-Variable in dem angegebenen env-Dictionary oder standardmäßig in os.environ gelesen wird. Dies ist die programmatische Entsprechung der Shell-PATH-Suche und wird intern von den p-Varianten der spawn- und exec-Funktionen verwendet.

import os

print("os.name:", os.name)
print("supports_bytes_environ:", os.supports_bytes_environ)
print("exec paths:", os.get_exec_path())

Übergabe der Umgebung an Kindprozesse über spawn und exec

Die spawn*e- und exec*e-Varianten akzeptieren einen env-Parameter, der die Kindprozessumgebung vollständig ersetzt, anstatt sie vom Elternprozess zu erben. Schlüssel und Werte in dieser Zuordnung müssen Strings sein; ungültige Typen führen dazu, dass die Funktion mit einem Rückgabewert von 127 fehlschlägt. Wenn env bereitgestellt wird, verwendet die PATH-Suche für das ausführbare Programm die neue Umgebung, nicht die des Elternprozesses os.environ.

Dieser Unterschied zwischen Erben (spawnl, spawnv, execl, execv) und Ersetzen (spawnle, spawnlpe, spawnve, spawnvpe, execle, execvpe) ist wesentlich für das Sandboxing von Kindprozessen oder das Einfügen von Konfiguration, ohne die Elternumgebung zu verschmutzen.

import os

child_env = dict(os.environ)
child_env["APP_MODE"] = "production"
# spawnvpe replaces the child environment entirely
status = os.spawnvpe(os.P_WAIT, "cp", ["cp", "index.html", "/dev/null"], child_env)
print("exit status:", status)

Was Sie prüfen sollten

  • os.environ.get gibt None für fehlende Variablen und '' für auf leeren String gesetzte Variablen zurück; diese sind nur durch Identitätsprüfung gegen None unterscheidbar.
  • os.environ[key] = value ruft setenv auf; del os.environ[key] ruft unsetenv auf; os.putenv aktualisiert os.environ nicht.
  • os.environb existiert nur, wenn os.supports_bytes_environ True ist (Unix); Änderungen an einer Abbildung aktualisieren die andere.
  • Der UTF-8-Modus erzwingt die UTF-8-Decodierung von Umgebungsvariablen unabhängig von der Lokalisierung; überprüfen Sie sys.flags.utf8_mode.
  • os.reload_environ ist ab Python 3.14 verfügbar und nicht threadsicher; gleichzeitige Lesezugriffe können leere Ergebnisse zurückgeben.
  • Der env-Parameter in spawn*e und exec*e muss String-Schlüssel und -Werte enthalten; ungültige Einträge verursachen den Rückgabewert 127.
  • Auf WebAssembly, Android und iOS sind prozessbezogene os-Funktionen nicht verfügbar oder gestubbt.

os.environb und os.getenvb sind nur unter Unix verfügbar (durch supports_bytes_environ abgesichert). os.reload_environ erfordert Python 3.14 oder später und ist ausdrücklich nicht threadsicher. Unter FreeBSD und macOS können häufige setenv-Aufrufe Speicherlecks auf C-Ebene verursachen. Der UTF-8-Modus kann nur beim Start des Interpreters aktiviert werden und kann zur Laufzeit nicht umgeschaltet werden. Die spawn/exec-Funktionen sind auf WebAssembly, Android und iOS nicht verfügbar.

Quellen

  1. Python: json ↗
  2. Python: pathlib ↗
  3. Python: os and working directories ↗
Nach oben ↑