TATECHATLAS
◎ Français
Programmation / Guide

Gestion des variables d'environnement en Python : os.environ, os.environb et considérations multiplateformes

Comment lire, modifier et synchroniser les variables d'environnement en Python avec os.environ et os.environb, gérer les différences d'encodage entre plateformes et transmettre l'environnement aux processus enfants.

Dans ce guide

os.environ est une copie instantanée de type dictionnaire de l'environnement du processus capturée au démarrage de l'interpréteur. Sa mutation appelle automatiquement setenv ou unsetenv, mais os.putenv ne met pas à jour la mappage. Sur Unix, os.environb fournit une vue en octets synchronisée avec os.environ. L'encodage des clés et valeurs dépend de l'encodage du système de fichiers ou du Mode UTF-8. os.reload_environ (Python 3.14+) rafraîchit le cache après des changements externes mais n'est pas thread-safe. Les processus enfants reçoivent l'environnement via le paramètre env des fonctions spawn*/exec*, qui doivent contenir des chaînes de caractères comme clés et valeurs.

Lecture des variables d'environnement via os.environ et os.getenv

os.environ est un objet de mappage représentant l'environnement du processus. Accéder à une clé qui n'existe pas soulève KeyError, tandis que os.environ.get(key, default) retourne la valeur par défaut. os.getenv(key, default=None) est un wrapper pratique qui retourne également None lorsque la variable est absente. La distinction critique réside entre une variable non définie (retourne None) et une variable définie avec une chaîne vide (retourne ''). Utiliser la vérité du résultat confond ces deux états, ce qui peut masquer silencieusement des erreurs de configuration dans les déploiements de production.

La documentation source indique que environ est un mappage où les clés et valeurs sont des chaînes. Sur les plateformes supportant l'accès aux environnements en octets, la représentation binaire est disponible via os.environb et os.getenvb. Pour la plupart des codes d'application, os.environ ou os.getenv suffit car l'interpréteur gère le décodage depuis l'encodage du système de fichiers ou le Mode UTF-8 automatiquement.

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))

Lorsque vous devez détecter si une variable est vraiment absente plutôt que définie avec une chaîne vide, utilisez os.environ.get(name) et vérifiez None plutôt que la vérité logique, car une chaîne vide est fausse mais sémantiquement différente d'une variable non définie.

Modification et suppression des variables via os.environ

Assigner à os.environ[key] appelle la fonction système sous-jacente setenv. Supprimer une clé appelle unsetenv. Les méthodes pop() et clear() déclenchent également unsetenv pour chaque entrée supprimée. Cette synchronisation automatique explique pourquoi la documentation recommande de modifier os.environ plutôt que d'appeler directement os.putenv, car putenv écrit dans le tableau C-level environ sans mettre à jour le mappage Python, laissant os.environ obsolète.

Sur certaines plateformes, y compris FreeBSD et macOS, des appels répétés à setenv ou putenv peuvent causer des fuites de mémoire dans le runtime C. Ceci est une préoccupation de niveau plateforme plutôt qu'un bug Python, mais cela signifie que les processus à long terme modifiant fréquemment les variables d'environnement devraient minimiser le nombre de clés distinctes qu'ils créent.

import os

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

Synchronisation de os.environ et os.environb

os.environb est une version en octets du mappage disponible uniquement lorsque os.supports_bytes_environ est True, ce qui est vrai sur les plateformes Unix. Les deux mappages sont maintenus synchronisés : modifier environb met à jour environ et vice versa. Cela signifie que vous pouvez écrire une valeur binaire à environb et lire la chaîne décodée depuis environ, ou l'inverse. Sur Windows, supports_bytes_environ est False et environb n'existe pas, donc le code ciblant les deux plateformes doit protéger l'accès avec ce drapeau.

La synchronisation utilise l'encodage du système de fichiers et son gestionnaire d'erreur pour la conversion entre octets et str. Si une valeur binaire contient des séquences qui ne peuvent pas être décodées selon l'encodage actuel, surrogateescape produit des surrogates isolés dans la vue str. Le passage aller-retour à travers les deux représentations préserve les octets originaux.

import os

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

Encodages : Mode UTF-8, fsencode/fsdecode, et getenvb

Lorsque le Mode UTF-8 de Python est actif (activé via -X utf8 ou PYTHONUTF8=1, ou automatiquement lorsque la locale est C ou POSIX), les variables d'environnement sont décodées en UTF-8 indépendamment de la locale système. En dehors du Mode UTF-8, l'encodage du système de fichiers gouverne le décodage. os.fsencode et os.fsdecode exposent explicitement ces conversions et constituent la méthode recommandée pour manipuler les octets de type chemin pouvant apparaître dans les valeurs d'environnement.

os.getenvb retourne les octets bruts d'une variable d'environnement sans aucune étape de décodage. C'est utile lorsque vous devez inspecter ou transmettre des valeurs qui peuvent contenir des octets invalides selon l'encodage actuel, ou lors de l'écriture de code portable devant éviter le tour implicite decode-then-re-encode.

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)

Cache d'environnement et os.reload_environ

La documentation est explicite : os.environ et os.environb sont un cache des variables d'environnement au moment où Python a démarré. Les modifications faites en dehors de l'interpréteur, ou via os.putenv et os.unsetenv, ne sont pas reflétées dans le mappage. os.reload_environ, ajouté en Python 3.14, rafraîchit les deux mappages depuis l'environnement actuel du processus. Avant 3.14, aucun mécanisme standard n'existait pour resynchroniser le cache après une modification externe.

Cela importe dans les scénarios où un processus parent ou un gestionnaire de signaux modifie l'environnement via des API de niveau C, ou lorsqu'une bibliothèque appelle putenv sans passer par os.environ. Sans reload_environ, les lectures ultérieures retournent des valeurs obsolètes.

import os

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

Erreurs et sécurité des threads lors du travail avec l'environnement

Toutes les fonctions du module os soulèvent OSError ou une sous-classe lorsque les arguments ont des types corrects mais sont rejetés par le système d'exploitation. Pour les opérations d'environnement, c'est rare car setenv et unsetenv réussissent pour les chaînes valides, mais des caractères de surrogat invalides dans les clés ou valeurs peuvent déclencher UnicodeEncodeError avant que l'appel système ne soit atteint.

os.reload_environ porte un avertissement explicite qu'il n'est pas thread-safe. Lire depuis os.environ, os.environb, ou appeler os.getenv pendant qu'un reload est en cours peut retourner un résultat vide. Dans les applications multi-threadées, serialisez l'accès à reload_environ ou évitez-le entièrement en gérant l'état de l'environnement uniquement via les mutations de os.environ.

import os

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

Portabilité multiplateforme : os.name, limitations de plateforme et PATH

os.name retourne 'posix' sur les systèmes de type Unix et 'nt' sur Windows. Sur WebAssembly, Android et iOS, de grandes parties du module os sont indisponibles ou se comportent différemment : les APIs de processus comme fork, execve et spawn sont absentes, et getuid et getpid peuvent être des stubs. Le code devant s'exécuter sur ces cibles doit vérifier os.name et os.supports_bytes_environ avant de compter sur le comportement spécifique à la plateforme.

os.get_exec_path retourne la liste des répertoires recherchés pour les exécutables, lisant depuis la variable PATH dans le dictionnaire env fourni ou dans os.environ par défaut. C'est l'équivalent programmatique de la recherche shell PATH et est utilisé en interne par les variantes p-des fonctions spawn et exec.

import os

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

Transmission de l'environnement aux processus enfants via spawn et exec

Les variantes spawn*e et exec*e acceptent un paramètre env qui remplace complètement l'environnement du processus enfant plutôt que d'hériter du parent. Les clés et valeurs dans ce mappage doivent être des chaînes ; des types invalides font échouer la fonction avec une valeur de retour de 127. Lorsque env est fourni, la recherche PATH pour l'exécutable utilise le nouvel environnement, pas le parent's os.environ.

Cette distinction entre héritage (spawnl, spawnv, execl, execv) et remplacement (spawnle, spawnlpe, spawnve, spawnvpe, execle, execvpe) est essentielle pour sandboxer les processus enfants ou injecter de la configuration sans polluer l'environnement parent.

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)

Points à vérifier

  • os.environ.get retourne None pour les variables absentes et '' pour les variables définies avec une chaîne vide ; ces deux cas ne sont distinguables que par une vérification d'identité contre None.
  • os.environ[key] = value appelle setenv ; del os.environ[key] appelle unsetenv ; os.putenv ne met pas à jour os.environ.
  • os.environb existe uniquement lorsque os.supports_bytes_environ est True (Unix) ; modifier un mappage met à jour l'autre.
  • Le Mode UTF-8 force le décodage UTF-8 des variables d'environnement indépendamment de la locale ; vérifiez sys.flags.utf8_mode.
  • os.reload_environ est disponible à partir de Python 3.14 et n'est pas thread-safe ; les lectures concurrentes peuvent retourner des résultats vides.
  • Le paramètre env dans spawn*e et exec*e doit contenir des clés et valeurs de type chaîne ; des entrées invalides causent une valeur de retour 127.
  • Sur WebAssembly, Android et iOS, les fonctions os liées aux processus sont indisponibles ou simulées.

os.environb et os.getenvb sont réservés à Unix (gérés par supports_bytes_environ). os.reload_environ nécessite Python 3.14 ou plus tard et n'est pas thread-safe. Sur FreeBSD et macOS, des appels fréquents à setenv peuvent provoquer des fuites de mémoire au niveau C. Le Mode UTF-8 ne peut être activé qu'au démarrage de l'interpréteur et ne peut pas être basculé à l'exécution. Les fonctions spawn/exec sont indisponibles sur WebAssembly, Android et iOS.

Sources

  1. Python: json ↗
  2. Python: pathlib ↗
  3. Python: os and working directories ↗
Retour en haut ↑