Les modules os et sys de Python
Maîtrisez les modules os et sys de Python : naviguez dans le système de fichiers, gérez les variables d'environnement et les arguments de ligne de commande.
Les modules os et sys font partie des outils de bibliothèque standard les plus essentiels de Python. os fait le lien entre Python et le système d'exploitation sous-jacent — il vous permet de naviguer dans les répertoires, d'inspecter et de définir des variables d'environnement, et de manipuler des fichiers et des chemins. sys fait le lien entre Python et l'interpréteur lui-même — il expose la liste d'arguments, le chemin de recherche des modules et des points d'ancrage pour contrôler la sortie de l'interpréteur. Ensemble, ils couvrent presque tout ce dont un script a besoin pour interagir avec l'environnement dans lequel il s'exécute.
Le module os
Importez os en haut de votre script :
import osAucune installation n'est nécessaire ; il est livré avec chaque distribution Python.
Travailler avec les répertoires
Obtenir et modifier le répertoire de travail courant
os.getcwd() retourne le chemin absolu du répertoire dans lequel votre script s'exécute. os.chdir() le modifie.
import os
# Print the current directory
print(os.getcwd())
# Example output: /Users/alice/projects
# Change to a different directory
os.chdir("/tmp")
print(os.getcwd())
# Output: /tmpLister le contenu d'un répertoire
os.listdir(path) retourne une liste de toutes les entrées (fichiers et sous-répertoires) dans path. Il ne descend pas récursivement dans les sous-répertoires.
import os
entries = os.listdir(".") # "." means current directory
for entry in sorted(entries):
print(entry)Pour distinguer les fichiers des répertoires, utilisez os.path.isfile() et os.path.isdir() :
import os
for entry in os.listdir("."):
if os.path.isdir(entry):
print(f"[DIR] {entry}")
else:
print(f"[FILE] {entry}")Créer et supprimer des répertoires
import os
# Create a single directory
os.mkdir("reports")
# Create nested directories in one call
os.makedirs("data/2024/january", exist_ok=True)
# exist_ok=True prevents an error if the directory already exists
# Remove an empty directory
os.rmdir("reports")
# Remove a full directory tree
import shutil
shutil.rmtree("data")Le paramètre exist_ok=True dans os.makedirs() est très utile dans les scripts susceptibles de s'exécuter plusieurs fois — sans lui, une deuxième exécution lève FileExistsError.
Parcourir une arborescence de répertoires
os.walk(top) génère un triplet (dirpath, dirnames, filenames) pour chaque répertoire de l'arborescence enracinée à top. C'est la méthode standard pour parcourir récursivement une structure de dossiers.
import os
for dirpath, dirnames, filenames in os.walk("project"):
level = dirpath.count(os.sep)
indent = " " * level
print(f"{indent}{os.path.basename(dirpath)}/")
for filename in filenames:
print(f"{indent} {filename}")Travailler avec les chemins de fichiers
Le sous-module os.path de Python contient des utilitaires portables de manipulation de chemins qui fonctionnent correctement sous Windows, macOS et Linux.
Assembler des composants de chemin
os.path.join() combine des parties d'un chemin en utilisant le séparateur correct pour le système d'exploitation courant.
import os
base = "/home/alice"
project = "myapp"
filename = "config.json"
full_path = os.path.join(base, project, filename)
print(full_path)
# Output: /home/alice/myapp/config.jsonNe construisez jamais des chemins par concaténation de chaînes comme base + "/" + filename — cela ne fonctionne pas sous Windows. Utilisez toujours os.path.join().
Décomposer un chemin
import os
path = "/home/alice/myapp/config.json"
print(os.path.dirname(path)) # /home/alice/myapp
print(os.path.basename(path)) # config.json
print(os.path.split(path)) # ('/home/alice/myapp', 'config.json')
print(os.path.splitext(path)) # ('/home/alice/myapp/config', '.json')os.path.splitext() est pratique lorsque vous devez retirer ou modifier une extension de fichier.
Vérifier si un chemin existe
import os
print(os.path.exists("/tmp")) # True (usually)
print(os.path.isfile("/tmp")) # False — it is a directory
print(os.path.isdir("/tmp")) # True
print(os.path.isabs("/tmp")) # True — it is an absolute pathObtenir le chemin absolu
os.path.abspath() résout les chemins relatifs par rapport au répertoire de travail courant :
import os
print(os.path.abspath("config.json"))
# Example output: /home/alice/myapp/config.jsonC'est utile lorsque vous devez stocker ou journaliser un chemin qui doit rester valide même si le répertoire de travail change ultérieurement.
La variable __file__ et les chemins relatifs au script
Un piège classique : un script qui ouvre "data.csv" fonctionne lorsqu'on l'exécute depuis son propre répertoire, mais échoue depuis un autre répertoire. La solution consiste à construire le chemin relatif au fichier script lui-même :
import os
# Directory that contains *this* script
HERE = os.path.dirname(os.path.abspath(__file__))
data_file = os.path.join(HERE, "data.csv")
with open(data_file, encoding="utf-8") as f:
content = f.read()Cette technique rend les scripts portables quel que soit le répertoire depuis lequel vous les lancez.
Variables d'environnement
Les variables d'environnement stockent des configurations qui vivent en dehors du code source — URL de bases de données, clés API, indicateurs de fonctionnalités, etc. Le mapping os.environ vous donne un accès en lecture et en écriture à l'environnement du processus courant.
Lire une variable d'environnement
import os
# Returns the value or None if not set
home = os.environ.get("HOME")
print(home)
# Example output: /home/alice
# Raise KeyError if not set (useful to fail fast on missing config)
path = os.environ["PATH"]Préférez os.environ.get(key) à os.environ[key] sauf si la variable est strictement requise et que le programme doit planter sans elle.
Lire avec une valeur par défaut
import os
debug = os.environ.get("DEBUG", "false")
port = int(os.environ.get("PORT", "8080"))
print(f"debug={debug}, port={port}")
# Output: debug=false, port=8080Définir et supprimer des variables d'environnement
import os
# Set a variable — affects only the current process and its children
os.environ["MY_APP_ENV"] = "production"
# Remove a variable
os.environ.pop("MY_APP_ENV", None) # None prevents KeyError if not presentLa définition de valeurs dans os.environ ne persiste pas après la fin du processus. Pour définir des variables d'environnement permanentes, modifiez votre profil shell (~/.bashrc, ~/.zshrc) ou utilisez un fichier .env chargé par une bibliothèque telle que python-dotenv.
Lister toutes les variables d'environnement
import os
for key, value in sorted(os.environ.items()):
print(f"{key}={value}")Exécuter des commandes shell avec os.system() et subprocess
os.system(command) exécute une commande shell et retourne son code de sortie, mais ne vous permet pas de capturer sa sortie. Pour tout ce qui dépasse un simple appel « lancer et oublier », utilisez plutôt le module subprocess.
import os
import subprocess
# Quick way — exit code only
exit_code = os.system("echo hello")
print("exit code:", exit_code) # 0 means success
# Better way — capture output
result = subprocess.run(
["echo", "hello"],
capture_output=True,
text=True,
)
print(result.stdout.strip()) # hellosubprocess.run() est plus puissant et plus sûr que os.system() car il évite l'interpréteur shell et vous permet de capturer stdout, stderr et le code de retour en tant qu'objets Python.
Utilitaires os pratiques
| Fonction | Ce qu'elle fait |
|---|---|
os.getcwd() | Répertoire de travail courant |
os.chdir(path) | Changer de répertoire de travail |
os.listdir(path) | Lister les entrées d'un répertoire |
os.mkdir(path) | Créer un répertoire |
os.makedirs(path, exist_ok=True) | Créer des répertoires imbriqués |
os.rmdir(path) | Supprimer un répertoire vide |
os.remove(path) | Supprimer un fichier |
os.rename(src, dst) | Renommer / déplacer un fichier |
os.walk(top) | Parcourir récursivement une arborescence |
os.environ | Mapping des variables d'environnement |
os.getpid() | ID du processus courant |
os.cpu_count() | Nombre de cœurs CPU logiques |
Le module sys
sys expose des informations sur l'interpréteur Python et vous donne des points d'ancrage pour contrôler son comportement.
import sysArguments de ligne de commande avec sys.argv
sys.argv est une liste de chaînes. sys.argv[0] est le nom du script ; les éléments suivants sont les arguments passés en ligne de commande.
Supposons que vous enregistriez ceci sous le nom greet.py et que vous exécutiez python greet.py Alice 42 :
import sys
script_name = sys.argv[0] # 'greet.py'
name = sys.argv[1] # 'Alice'
age = sys.argv[2] # '42' — always a string
print(f"Hello, {name}! You are {age} years old.")
# Output: Hello, Alice! You are 42 years old.Validez toujours sys.argv avant d'accéder aux indices — une IndexError fera planter le script si l'utilisateur oublie un argument :
import sys
if len(sys.argv) != 3:
print(f"Usage: python {sys.argv[0]} <name> <age>")
sys.exit(1)
name = sys.argv[1]
age = sys.argv[2]
print(f"Hello, {name}! You are {age} years old.")Pour l'analyse d'arguments complexes, préférez le module argparse de la bibliothèque standard — il génère automatiquement une sortie --help.
Quitter l'interpréteur avec sys.exit()
sys.exit(code) lève SystemExit et termine l'interpréteur. Par convention, le code de sortie 0 signifie le succès ; toute valeur non nulle signale une erreur.
import sys
answer = input("Continue? (y/n): ")
if answer.lower() != "y":
print("Goodbye!")
sys.exit(0)
print("Continuing...")Vous pouvez intercepter SystemExit dans un bloc try/except si vous avez besoin d'exécuter un nettoyage avant la fin du programme, mais en général l'instruction with (pour les descripteurs de fichiers, les connexions réseau, etc.) gère automatiquement le nettoyage.
Informations sur la version de Python
import sys
print(sys.version)
# Example: 3.10.15 (main, ...) [GCC 11.4.0]
print(sys.version_info)
# sys.version_info(major=3, minor=10, micro=15, ...)
# Guard against running on an unsupported Python version
if sys.version_info < (3, 8):
sys.exit("This script requires Python 3.8 or later.")sys.version_info est un n-uplet nommé, vous pouvez donc le comparer directement à un n-uplet d'entiers.
Le chemin de recherche des modules (sys.path)
Lorsque vous écrivez import mymodule, Python parcourt chaque répertoire de sys.path dans l'ordre jusqu'à trouver un fichier correspondant. La liste commence par le répertoire du script (ou une chaîne vide pour les sessions interactives), suivi des entrées PYTHONPATH, puis de la bibliothèque standard et des site-packages.
import sys
for p in sys.path:
print(p)Vous pouvez ajouter des éléments à sys.path à l'exécution pour importer des modules depuis des emplacements non standard :
import sys
import os
# Add a sibling directory to the search path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "libs"))
import mymodule # now found in ./libs/mymodule.pyModifier sys.path est une solution rapide pour le développement local, mais pour les paquets distribuables, utilisez plutôt pip et un fichier pyproject.toml approprié.
Flux standard
sys.stdin, sys.stdout et sys.stderr sont des objets de type fichier connectés aux trois flux standard. Vous pouvez les rediriger pour capturer ou supprimer la sortie.
import sys
# Write to stdout (same as print, but more explicit)
sys.stdout.write("Hello, stdout\n")
# Write to stderr (errors and diagnostics)
sys.stderr.write("Warning: something looks off\n")Un schéma courant dans les scripts consiste à rediriger sys.stdout vers un fichier pour capturer toute la sortie de print() :
import sys
with open("output.log", "w", encoding="utf-8") as log:
original_stdout = sys.stdout
sys.stdout = log
print("This goes to the log file.")
sys.stdout = original_stdout
print("This goes back to the terminal.")Attributs sys utiles
| Attribut / Fonction | Ce qu'il retourne |
|---|---|
sys.argv | Liste des arguments de ligne de commande |
sys.version | Chaîne de version Python |
sys.version_info | N-uplet nommé de (major, minor, micro, ...) |
sys.platform | Identifiant de plateforme ("linux", "darwin", "win32") |
sys.path | Chemin de recherche des modules (liste de chaînes) |
sys.modules | Dictionnaire de tous les modules actuellement importés |
sys.stdin | Flux d'entrée standard |
sys.stdout | Flux de sortie standard |
sys.stderr | Flux d'erreur standard |
sys.exit(code) | Quitter l'interpréteur avec le code de statut donné |
sys.getrecursionlimit() | Profondeur de récursion maximale (défaut 1000) |
sys.maxsize | Valeur maximale d'un int sur cette plateforme |
Combiner os et sys en pratique
Les scripts réels utilisent souvent les deux modules ensemble. Voici un exemple petit mais réaliste : un script qui parcourt un répertoire à la recherche de fichiers .log et affiche un résumé.
import os
import sys
def summarize_logs(directory):
if not os.path.isdir(directory):
sys.stderr.write(f"Error: '{directory}' is not a directory.\n")
sys.exit(1)
log_files = [
f for f in os.listdir(directory)
if f.endswith(".log") and os.path.isfile(os.path.join(directory, f))
]
if not log_files:
print("No .log files found.")
return
print(f"Found {len(log_files)} log file(s) in '{directory}':")
for name in sorted(log_files):
full_path = os.path.join(directory, name)
size = os.path.getsize(full_path)
print(f" {name} ({size} bytes)")
if len(sys.argv) != 2:
print(f"Usage: python {sys.argv[0]} <directory>")
sys.exit(1)
summarize_logs(sys.argv[1])Exécutez-le avec python summarize.py /var/log et il affiche le nom et la taille en octets de chaque fichier .log dans ce répertoire.
os vs pathlib — Lequel utiliser ?
Python 3.4 a introduit pathlib.Path, une alternative orientée objet à os.path. Les deux approches sont correctes ; le choix est surtout une question de préférence stylistique.
| Tâche | Style os | Style pathlib |
|---|---|---|
| Assembler des chemins | os.path.join(a, b) | Path(a) / b |
| Obtenir le nom de fichier | os.path.basename(p) | Path(p).name |
| Obtenir l'extension | os.path.splitext(p)[1] | Path(p).suffix |
| Vérifier l'existence | os.path.exists(p) | Path(p).exists() |
| Lire un fichier texte | open(p).read() | Path(p).read_text() |
| Lister un répertoire | os.listdir(p) | list(Path(p).iterdir()) |
pathlib tend à produire un code plus lisible pour les scripts intensifs en manipulation de chemins ; os.path est familier et supporté partout où Python 3 s'exécute. Le module sys n'a pas d'équivalent pathlib — c'est toujours import sys.
Pratique
Chapitres associés
- Modules Python — créer et importer vos propres modules
- Gestion des fichiers Python — lire et écrire des fichiers
- Try Except Python — gérer les erreurs des opérations de fichiers et du système d'exploitation
- Variables Python — portée et nommage des variables
- Portée Python — comment Python résout les noms entre les différentes portées