29. Interagir avec le système d’exploitation : sys et os
Les programmes Python n’existent pas en vase clos : ils s’exécutent sur un système d’exploitation qui gère les fichiers, les répertoires, les paramètres d’environnement, et la manière dont les programmes démarrent et communiquent. Les modules sys et os fournissent des outils pour interagir avec cet environnement, en permettant à vos programmes d’accepter des arguments en ligne de commande, de lire des variables d’environnement, de naviguer dans le système de fichiers, et de créer ou supprimer des répertoires.
Comprendre ces modules transforme vos scripts Python : au lieu d’un code isolé, vous obtenez des programmes capables de s’intégrer au système au sens large, de répondre aux entrées utilisateur au démarrage, et de gérer des fichiers et des dossiers par programmation.
29.1) Arguments en ligne de commande et utilisation de sys.argv
Lorsque vous exécutez un script Python depuis le terminal ou l’invite de commandes, vous pouvez lui passer des informations supplémentaires : ce sont les arguments en ligne de commande(command-line arguments). Par exemple :
python greet.py Alice 25Ici, greet.py est le nom du script, et Alice et 25 sont des arguments passés au programme. Le module sys donne accès à ces arguments via sys.argv, une liste contenant le nom du script et tous les arguments sous forme de chaînes de caractères.
29.1.1) Qu’est-ce que sys.argv ?
sys.argv est une liste dans laquelle :
sys.argv[0]est toujours le nom du script exécutésys.argv[1],sys.argv[2], etc., sont les arguments passés après le nom du script- Tous les éléments sont des chaînes, même s’ils ressemblent à des nombres
Créons un script simple pour voir comment cela fonctionne :
# show_args.py
import sys
print("Script name:", sys.argv[0])
print("Number of arguments:", len(sys.argv))
print("All arguments:", sys.argv)Si vous exécutez ce script avec :
python show_args.py hello world 123Output:
Script name: show_args.py
Number of arguments: 4
All arguments: ['show_args.py', 'hello', 'world', '123']Remarquez que sys.argv contient 4 éléments : le nom du script plus trois arguments. Le nombre 123 est stocké comme la chaîne '123', et non comme un entier.
29.1.2) Utiliser des arguments en ligne de commande dans des programmes
Les arguments en ligne de commande permettent aux utilisateurs de personnaliser le comportement d’un programme sans modifier le code. Voici un programme de salutation qui utilise le premier argument comme nom :
# greet.py
import sys
if len(sys.argv) < 2:
print("Usage: python greet.py <name>")
sys.exit(1) # Quitter avec un code d’erreur
name = sys.argv[1]
print(f"Hello, {name}!")En l’exécutant :
python greet.py AliceOutput:
Hello, Alice!Si vous oubliez de fournir un nom :
python greet.pyOutput:
Usage: python greet.py <name>Le programme vérifie si suffisamment d’arguments ont été fournis. Si ce n’est pas le cas, il affiche un message d’usage et se termine avec sys.exit(1). Le nombre 1 est un code de sortie(exit code) : par convention, 0 signifie succès et des valeurs non nulles indiquent des erreurs. Cela aide d’autres programmes ou scripts à détecter si votre programme s’est exécuté correctement.
29.1.3) Convertir des arguments vers d’autres types
Puisque tous les arguments arrivent sous forme de chaînes, vous devez souvent les convertir. Voici un programme qui calcule l’aire d’un rectangle :
# area.py
import sys
if len(sys.argv) < 3:
print("Usage: python area.py <width> <height>")
sys.exit(1)
try:
width = float(sys.argv[1])
height = float(sys.argv[2])
except ValueError:
print("Error: Width and height must be numbers")
sys.exit(1)
area = width * height
print(f"Area: {area}")En l’exécutant :
python area.py 5.5 3.2Output:
Area: 17.6Si l’utilisateur fournit une entrée invalide :
python area.py five threeOutput:
Error: Width and height must be numbersLe bloc try-except (du chapitre 25) gère les erreurs de conversion de manière élégante, en fournissant un retour utile plutôt que de planter avec une traceback.
29.2) Obtenir des informations sur l’interpréteur et l’exécution avec sys
Le module sys fournit des informations sur l’interpréteur Python lui-même et sur l’environnement d’exécution. C’est utile pour le débogage(debugging), la journalisation(logging) ou l’écriture de code qui s’adapte à différentes versions de Python ou plateformes.
29.2.1) Informations sur la version de Python
sys.version et sys.version_info vous indiquent quelle version de Python exécute votre code :
import sys
print("Python version string:", sys.version)
print("Version info:", sys.version_info)
print(f"Major version: {sys.version_info.major}")
print(f"Minor version: {sys.version_info.minor}")Output (example):
Python version string: 3.11.4 (main, Jul 5 2023, 13:45:01) [GCC 11.2.0]
Version info: sys.version_info(major=3, minor=11, micro=4, releaselevel='final', serial=0)
Major version: 3
Minor version: 11sys.version est une chaîne lisible par un humain, tandis que sys.version_info est un tuple nommé que vous pouvez comparer par programmation :
import sys
if sys.version_info < (3, 8):
print("This program requires Python 3.8 or higher")
sys.exit(1)
print("Python version is compatible")Cela garantit que votre programme ne s’exécute que sur des versions de Python prises en charge.
29.2.2) Informations sur la plateforme
sys.platform identifie le système d’exploitation :
import sys
print("Platform:", sys.platform)
if sys.platform == "win32":
print("Running on Windows")
elif sys.platform == "darwin":
print("Running on macOS")
elif sys.platform.startswith("linux"):
print("Running on Linux")
else:
print("Running on another platform")Output (on Linux):
Platform: linux
Running on LinuxCela vous permet d’écrire du code spécifique à une plateforme lorsque c’est nécessaire, par exemple en utilisant des chemins de fichiers ou des commandes système différents.
29.2.3) Chemin de recherche des modules
sys.path est une liste de répertoires que Python parcourt lorsqu’il importe des modules :
import sys
print("Module search paths:")
for path in sys.path:
print(f" {path}")Output (example):
Module search paths:
/home/user/projects
/usr/lib/python3.11
/usr/lib/python3.11/lib-dynload
/home/user/.local/lib/python3.11/site-packagesLa première entrée est généralement le répertoire contenant votre script. Python recherche ces chemins dans l’ordre lorsque vous utilisez import. Comprendre sys.path aide à déboguer des erreurs d’import ou à ajouter des répertoires de modules personnalisés.
29.2.4) Quitter des programmes avec des codes de sortie
Nous avons vu sys.exit() utilisé pour arrêter des programmes. Vous pouvez passer un code de sortie pour indiquer un succès ou un échec :
import sys
def process_data(filename):
try:
with open(filename) as f:
data = f.read()
# Traiter les données...
return True
except FileNotFoundError:
print(f"Error: File '{filename}' not found", file=sys.stderr)
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python script.py <filename>", file=sys.stderr)
sys.exit(1)
success = process_data(sys.argv[1])
sys.exit(0 if success else 1)Les codes de sortie suivent les conventions Unix :
0signifie succès- Des valeurs non nulles indiquent différents types d’erreurs
- D’autres programmes peuvent vérifier ces codes pour déterminer si votre programme a réussi
29.3) Accéder aux variables d’environnement avec os
Les variables d’environnement(environment variables) sont des paires clé-valeur définies par le système d’exploitation ou l’utilisateur, que les programmes peuvent lire. Elles servent à la configuration, au stockage de chemins, de clés d’API, et d’autres paramètres qui ne devraient pas être codés en dur.
29.3.1) Lire des variables d’environnement
Le module os fournit os.environ, un objet de type dictionnaire contenant toutes les variables d’environnement :
import os
# Obtenir une variable d’environnement spécifique
home = os.environ.get('HOME') # Sur Unix/Linux/macOS
print(f"Home directory: {home}")
# Renvoie None si la variable n’existe pas
api_key = os.environ.get('MY_API_KEY')
print(f"API key: {api_key}")Output (on Linux):
Home directory: /home/alice
API key: NoneVous pouvez fournir une valeur par défaut :
import os
# Obtenir une variable d’environnement avec une valeur par défaut
log_level = os.environ.get('LOG_LEVEL', 'INFO')
print(f"Log level: {log_level}")Output (if LOG_LEVEL not set):
Log level: INFO29.3.2) Variables d’environnement courantes
Différents systèmes d’exploitation fournissent des variables d’environnement standard :
import os
# Variables multiplateformes
print("Path:", os.environ.get('PATH'))
# Unix/Linux/macOS
print("User:", os.environ.get('USER'))
print("Home:", os.environ.get('HOME'))
print("Shell:", os.environ.get('SHELL'))
# Windows
print("User", os.environ.get('USERNAME'))
print("User Profile:", os.environ.get('USERPROFILE'))
print("Temp:", os.environ.get('TEMP'))PATH est particulièrement importante : elle liste les répertoires dans lesquels le système recherche des programmes exécutables. Lorsque vous tapez une commande comme python, le système recherche dans ces répertoires.
29.3.3) Définir des variables d’environnement
Vous pouvez modifier des variables d’environnement pour votre programme et tous les sous-processus qu’il crée :
import os
# Définir une variable d’environnement
os.environ['MY_CONFIG'] = 'production'
# La relire
print(os.environ.get('MY_CONFIG')) # Output: production
# Supprimer une variable d’environnement
del os.environ['MY_CONFIG']Important : les modifications de os.environ n’affectent que le processus Python courant et les programmes qu’il lance. Elles ne persistent pas après la fin de votre programme et n’affectent pas les autres programmes.
29.4) Travailler avec les chemins de fichiers et les répertoires (os.path, os.getcwd)
Gérer correctement les chemins de fichiers est crucial pour les programmes qui travaillent avec des fichiers. Les modules os et os.path fournissent des outils pour construire, manipuler et interroger des chemins de manière indépendante de la plateforme.
29.4.1) Obtenir le répertoire de travail actuel
Le répertoire de travail actuel(current working directory) (CWD) est le dossier que votre programme considère comme point de départ pour les chemins relatifs :
import os
cwd = os.getcwd()
print(f"Current working directory: {cwd}")Output (example):
Current working directory: /home/alice/projects/myappLorsque vous ouvrez un fichier avec un chemin relatif comme 'data.txt', Python cherche dans le répertoire de travail actuel. Comprendre le CWD aide à déboguer des erreurs « fichier introuvable ».
29.4.2) Changer le répertoire actuel
Vous pouvez changer le répertoire de travail avec os.chdir() :
import os
original = os.getcwd()
print("Original directory:", original)
# Changer vers un autre répertoire
os.chdir('/tmp')
print("New directory:", os.getcwd())
# Revenir en arrière
os.chdir(original)
print("Back to:", os.getcwd())Output:
Original directory: /home/alice/projects
New directory: /tmp
Back to: /home/alice/projectsNote : au chapitre 28, vous avez appris contextlib.chdir(), qui restaure automatiquement le répertoire original. Pour des changements de répertoire simples, privilégiez l’utilisation du gestionnaire de contexte :
from contextlib import chdir
with chdir('/tmp'):
print("Temporarily in:", os.getcwd())
# Automatically restoredCela garantit que le répertoire est toujours restauré, même si une erreur se produit.
29.4.3) Construire des chemins avec os.path.join()
Différents systèmes d’exploitation utilisent différents séparateurs de chemin :
- Unix/Linux/macOS :
/(barre oblique) - Windows :
\(barre oblique inversée)
os.path.join() construit correctement les chemins pour la plateforme actuelle :
import os
# Construire un chemin vers un fichier dans un sous-répertoire
data_dir = 'data'
filename = 'users.txt'
filepath = os.path.join(data_dir, filename)
print(f"File path: {filepath}")Output (on Unix/Linux/macOS):
File path: data/users.txtOutput (on Windows):
File path: data\users.txtVous pouvez assembler plusieurs composants :
import os
base = '/home/alice'
project = 'myapp'
subdir = 'data'
file = 'config.json'
full_path = os.path.join(base, project, subdir, file)
print(full_path) # Output: /home/alice/myapp/data/config.jsonL’utilisation de os.path.join() rend votre code portable entre systèmes d’exploitation.
29.4.4) Vérifier si des chemins existent
Avant de travailler avec des fichiers ou des répertoires, vérifiez s’ils existent :
import os
path = 'data.txt'
if os.path.exists(path):
print(f"'{path}' exists")
else:
print(f"'{path}' does not exist")Vous pouvez aussi vérifier spécifiquement s’il s’agit de fichiers ou de répertoires :
import os
path = 'mydir'
if os.path.isfile(path):
print(f"'{path}' is a file")
elif os.path.isdir(path):
print(f"'{path}' is a directory")
elif os.path.exists(path):
print(f"'{path}' exists but is neither a file nor directory")
else:
print(f"'{path}' does not exist")Ces vérifications évitent des erreurs lorsqu’on tente d’ouvrir des fichiers inexistants ou de lister des répertoires inexistants.
29.4.5) Obtenir des chemins absolus
os.path.abspath() convertit des chemins relatifs en chemins absolus :
import os
relative_path = 'data/users.txt'
absolute_path = os.path.abspath(relative_path)
print(f"Relative: {relative_path}")
print(f"Absolute: {absolute_path}")Output (example):
Relative: data/users.txt
Absolute: /home/alice/projects/myapp/data/users.txtC’est utile pour la journalisation, les messages d’erreur, ou lorsque vous devez connaître l’emplacement exact d’un fichier.
29.4.6) Découper des chemins en composants
os.path.split() sépare un chemin en répertoire et nom de fichier :
import os
path = '/home/alice/projects/data.txt'
directory, filename = os.path.split(path)
print(f"Directory: {directory}")
print(f"Filename: {filename}")Output:
Directory: /home/alice/projects
Filename: data.txtos.path.basename() récupère uniquement le nom de fichier, et os.path.dirname() récupère uniquement le répertoire :
import os
path = '/home/alice/projects/data.txt'
print(f"Basename: {os.path.basename(path)}") # Output: data.txt
print(f"Dirname: {os.path.dirname(path)}") # Output: /home/alice/projects29.4.7) Découper les extensions de fichier
os.path.splitext() sépare le nom de fichier de son extension :
import os
filename = 'report.pdf'
name, extension = os.path.splitext(filename)
print(f"Name: {name}") # Output: report
print(f"Extension: {extension}") # Output: .pdfC’est utile pour traiter des fichiers selon leur type :
import os
files = ['data.csv', 'image.png', 'document.txt', 'script.py']
for file in files:
name, ext = os.path.splitext(file)
if ext == '.csv':
print(f"Process CSV file: {file}")
elif ext == '.png':
print(f"Process image file: {file}")Output:
Process CSV file: data.csv
Process image file: image.png29.5) Lister, créer et supprimer des fichiers et des répertoires
Le module os fournit des fonctions pour manipuler le système de fichiers : lister le contenu des répertoires, créer de nouveaux répertoires, et supprimer des fichiers et des dossiers.
29.5.1) Lister le contenu d’un répertoire
os.listdir() renvoie une liste de tous les éléments d’un répertoire :
import os
# Lister le contenu du répertoire courant
contents = os.listdir('.')
print("Current directory contents:")
for item in contents:
print(f" {item}")Output (example):
Current directory contents:
script.py
data.txt
mydir
README.mdLa liste inclut à la fois des fichiers et des répertoires. Pour les distinguer :
import os
contents = os.listdir('.')
print("Files:")
for item in contents:
if os.path.isfile(item):
print(f" {item}")
print("\nDirectories:")
for item in contents:
if os.path.isdir(item):
print(f" {item}")Output:
Files:
script.py
data.txt
README.md
Directories:
mydir29.5.2) Créer des répertoires
os.mkdir() crée un seul répertoire :
import os
new_dir = 'output'
if not os.path.exists(new_dir):
os.mkdir(new_dir)
print(f"Created directory: {new_dir}")
else:
print(f"Directory already exists: {new_dir}")Output:
Created directory: outputImportant : os.mkdir() échoue si le répertoire parent n’existe pas. Par exemple, tenter de créer 'data/output' lorsque 'data' n’existe pas lèvera une erreur.
os.makedirs() crée tous les répertoires parents nécessaires :
import os
nested_dir = 'data/processed/2024'
if not os.path.exists(nested_dir):
os.makedirs(nested_dir)
print(f"Created directory structure: {nested_dir}")Output:
Created directory structure: data/processed/2024Cela crée data, puis data/processed, puis data/processed/2024 s’ils n’existent pas.
29.5.3) Supprimer des fichiers
os.remove() supprime un fichier :
import os
filename = 'temp.txt'
# Créer un fichier temporaire
with open(filename, 'w') as f:
f.write('Temporary data')
print(f"File exists: {os.path.exists(filename)}") # Output: True
# Supprimer le fichier
os.remove(filename)
print(f"File exists: {os.path.exists(filename)}") # Output: FalseAvertissement : os.remove() supprime définitivement les fichiers ; ils ne vont pas dans une corbeille.
29.5.4) Supprimer des répertoires
os.rmdir() supprime un répertoire vide :
import os
directory = 'empty_dir'
# Créer puis supprimer un répertoire vide
os.mkdir(directory)
print(f"Created: {directory}")
os.rmdir(directory)
print(f"Removed: {directory}")os.rmdir() échoue si le répertoire contient des fichiers. Pour supprimer un répertoire et tout son contenu, vous devez d’abord supprimer les fichiers :
import os
def remove_directory_contents(directory):
"""Supprimer tous les fichiers d’un répertoire, puis supprimer le répertoire.
Remarque : échoue si le répertoire contient des sous-répertoires.
"""
if not os.path.exists(directory):
print(f"Directory does not exist: {directory}")
return
# Supprimer tous les fichiers du répertoire
for item in os.listdir(directory):
item_path = os.path.join(directory, item)
if os.path.isfile(item_path):
os.remove(item_path)
print(f"Removed file: {item_path}")
# Supprimer le répertoire désormais vide
os.rmdir(directory)
print(f"Removed directory: {directory}")
# Exemple d’utilisation
test_dir = 'test_data'
os.makedirs(test_dir, exist_ok=True)
# Créer quelques fichiers de test
with open(os.path.join(test_dir, 'file1.txt'), 'w') as f:
f.write('test')
with open(os.path.join(test_dir, 'file2.txt'), 'w') as f:
f.write('test')
# Tout supprimer
remove_directory_contents(test_dir)Output:
Removed file: test_data/file1.txt
Removed file: test_data/file2.txt
Removed directory: test_dataNote : pour une suppression de répertoire plus complexe (y compris les sous-répertoires), le module shutil de Python fournit shutil.rmtree(), mais cela dépasse notre périmètre actuel.
29.5.5) Renommer des fichiers et des répertoires
os.rename() renomme ou déplace des fichiers et des répertoires :
import os
# Renommer un fichier
old_name = 'draft.txt'
new_name = 'final.txt'
# Créer un fichier de test
with open(old_name, 'w') as f:
f.write('content')
os.rename(old_name, new_name)
print(f"Renamed '{old_name}' to '{new_name}'")Vous pouvez aussi déplacer des fichiers vers d’autres répertoires :
import os
# Créer des répertoires et un fichier
os.makedirs('source', exist_ok=True)
os.makedirs('destination', exist_ok=True)
with open('source/file.txt', 'w') as f:
f.write('content')
# Déplacer le fichier vers un autre répertoire
os.rename('source/file.txt', 'destination/file.txt')
print("Moved file to destination directory")Les modules sys et os donnent à vos programmes Python la capacité d’interagir avec le système d’exploitation, d’accepter des entrées en ligne de commande, de lire la configuration, et de gérer des fichiers et des répertoires. Ces capacités transforment des scripts simples en outils puissants en ligne de commande qui s’intègrent de manière transparente à l’environnement système au sens large.