W3docs

Moduli os e sys di Python

Padroneggia i moduli os e sys di Python: naviga il file system, gestisci le variabili d'ambiente, ispeziona lo stato dell'interprete e gli argomenti della riga di comando.

I moduli os e sys sono due degli strumenti della libreria standard di Python più essenziali. os collega Python al sistema operativo sottostante — permettendoti di navigare nelle directory, ispezionare e impostare variabili d'ambiente, e manipolare file e percorsi. sys collega Python all'interprete stesso — esponendo l'elenco degli argomenti, il percorso di ricerca dei moduli e gli hook per controllare l'uscita dall'interprete. Insieme coprono quasi tutto ciò di cui uno script ha bisogno per interagire con l'ambiente in cui viene eseguito.

Il modulo os

Importa os all'inizio del tuo script:

import os

Non è necessaria alcuna installazione; è incluso in ogni distribuzione Python.

Lavorare con le directory

Ottenere e cambiare la directory di lavoro corrente

os.getcwd() restituisce il percorso assoluto della directory in cui è in esecuzione il tuo script. os.chdir() lo modifica.

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: /tmp

Elencare il contenuto di una directory

os.listdir(path) restituisce un elenco di tutte le voci (file e sottodirectory) in path. Non ricorre nelle sottodirectory.

import os

entries = os.listdir(".")   # "." means current directory
for entry in sorted(entries):
    print(entry)

Per distinguere i file dalle directory si usano os.path.isfile() e os.path.isdir():

import os

for entry in os.listdir("."):
    if os.path.isdir(entry):
        print(f"[DIR]  {entry}")
    else:
        print(f"[FILE] {entry}")

Creare e rimuovere directory

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

Il parametro exist_ok=True in os.makedirs() è molto utile negli script che potrebbero essere eseguiti più di una volta — senza di esso, una seconda esecuzione genera FileExistsError.

Attraversare un albero di directory

os.walk(top) genera una tripla (dirpath, dirnames, filenames) per ogni directory nell'albero che ha radice in top. È il modo standard per ricorrere in una struttura di cartelle.

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

Lavorare con i percorsi dei file

Il sotto-modulo os.path di Python contiene utilità portabili per la manipolazione dei percorsi che funzionano correttamente su Windows, macOS e Linux.

Unire componenti di un percorso

os.path.join() combina parti di un percorso usando il separatore corretto per il sistema operativo corrente.

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.json

Non costruire mai percorsi con la concatenazione di stringhe come base + "/" + filename — si rompe su Windows. Usa sempre os.path.join().

Dividere un percorso

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() è comodo quando devi rimuovere o cambiare un'estensione di file.

Verificare se un percorso esiste

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 path

Ottenere il percorso assoluto

os.path.abspath() risolve i percorsi relativi rispetto alla directory di lavoro corrente:

import os

print(os.path.abspath("config.json"))
# Example output: /home/alice/myapp/config.json

Questo è utile quando devi memorizzare o registrare un percorso che deve rimanere valido anche se la directory di lavoro cambia in seguito.

La variabile __file__ e i percorsi relativi allo script

Un errore comune: uno script che apre "data.csv" funziona quando lo esegui dalla sua stessa directory, ma si interrompe da una directory diversa. La soluzione è costruire il percorso relativo al file dello script stesso:

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

Questa tecnica rende gli script portabili indipendentemente da quale directory li avvii.

Variabili d'ambiente

Le variabili d'ambiente memorizzano la configurazione che vive al di fuori del codice sorgente — URL del database, chiavi API, flag di funzionalità e così via. La mappatura os.environ ti consente di leggere e scrivere nell'ambiente del processo corrente.

Leggere una variabile d'ambiente

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"]

Preferisci os.environ.get(key) rispetto a os.environ[key] a meno che la variabile non sia strettamente necessaria e il programma debba arrestarsi senza di essa.

Leggere con un valore predefinito

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=8080

Impostare ed eliminare variabili d'ambiente

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 present

L'impostazione dei valori di os.environ non persiste dopo la chiusura del processo. Per impostare variabili d'ambiente permanenti, modifica il profilo della tua shell (~/.bashrc, ~/.zshrc) oppure usa un file .env caricato da una libreria come python-dotenv.

Elencare tutte le variabili d'ambiente

import os

for key, value in sorted(os.environ.items()):
    print(f"{key}={value}")

Eseguire comandi shell con os.system() e subprocess

os.system(command) esegue un comando shell e restituisce il suo codice di uscita, ma non ti offre alcun modo per catturarne l'output. Per qualsiasi cosa al di là di una semplice chiamata fire-and-forget, usa invece il modulo 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())   # hello

subprocess.run() è più potente e sicuro di os.system() perché evita l'interprete della shell e ti permette di catturare stdout, stderr e il codice di ritorno come oggetti Python.

Utilità os più usate

FunzioneCosa fa
os.getcwd()Directory di lavoro corrente
os.chdir(path)Cambia la directory di lavoro
os.listdir(path)Elenca le voci di una directory
os.mkdir(path)Crea una directory
os.makedirs(path, exist_ok=True)Crea directory annidate
os.rmdir(path)Rimuove una directory vuota
os.remove(path)Elimina un file
os.rename(src, dst)Rinomina / sposta un file
os.walk(top)Attraversa ricorsivamente un albero di directory
os.environMappatura delle variabili d'ambiente
os.getpid()ID del processo corrente
os.cpu_count()Numero di core CPU logici

Il modulo sys

sys espone informazioni sull'interprete Python e fornisce hook per controllarne il comportamento.

import sys

Argomenti della riga di comando con sys.argv

sys.argv è un elenco di stringhe. sys.argv[0] è il nome dello script; gli elementi successivi sono gli argomenti passati dalla riga di comando.

Supponiamo di salvare questo come greet.py ed eseguirlo con 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.

Valida sempre sys.argv prima di accedere agli indici — un IndexError causerà l'interruzione dello script se l'utente dimentica un argomento:

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

Per il parsing di argomenti complessi, preferisci il modulo argparse nella libreria standard — genera automaticamente l'output --help.

Uscire dall'interprete con sys.exit()

sys.exit(code) genera SystemExit e termina l'interprete. Per convenzione, il codice di uscita 0 significa successo; qualsiasi valore diverso da zero segnala un errore.

import sys

answer = input("Continue? (y/n): ")
if answer.lower() != "y":
    print("Goodbye!")
    sys.exit(0)

print("Continuing...")

Puoi intercettare SystemExit in un blocco try/except se devi eseguire operazioni di pulizia prima che il programma termini, ma di solito l'istruzione with (per gli handle di file, le connessioni di rete, ecc.) gestisce automaticamente la pulizia.

Informazioni sulla versione di 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 è una named tuple, quindi puoi confrontarla direttamente con una tupla di interi.

Il percorso di ricerca dei moduli (sys.path)

Quando scrivi import mymodule, Python cerca in ogni directory in sys.path nell'ordine finché non trova un file corrispondente. L'elenco inizia con la directory dello script (o una string vuota per le sessioni interattive), seguita dalle voci di PYTHONPATH, e poi dalla libreria standard e dai pacchetti del sito.

import sys

for p in sys.path:
    print(p)

Puoi aggiungere elementi a sys.path in fase di esecuzione per importare moduli da posizioni 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.py

Modificare sys.path è una soluzione rapida per lo sviluppo locale, ma per i pacchetti distribuibili usa pip e un apposito pyproject.toml.

Stream standard

sys.stdin, sys.stdout e sys.stderr sono oggetti simili a file collegati ai tre stream standard. Puoi reindirizzarli per catturare o sopprimere l'output.

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 pattern comune negli script è reindirizzare sys.stdout a un file per catturare tutto l'output di 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.")

Attributi sys più utili

Attributo / FunzioneCosa restituisce
sys.argvElenco degli argomenti della riga di comando
sys.versionstring della versione Python
sys.version_infoNamed tuple di (major, minor, micro, ...)
sys.platformIdentificatore della piattaforma ("linux", "darwin", "win32")
sys.pathPercorso di ricerca dei moduli (elenco di stringhe)
sys.modulesDizionario di tutti i moduli attualmente importati
sys.stdinStream di input standard
sys.stdoutStream di output standard
sys.stderrStream di errore standard
sys.exit(code)Esce dall'interprete con il codice di stato dato
sys.getrecursionlimit()Profondità massima di ricorsione (predefinita 1000)
sys.maxsizeValore massimo di un int su questa piattaforma

Combinare os e sys in pratica

Gli script reali usano spesso entrambi i moduli insieme. Ecco un esempio piccolo ma realistico: uno script che scansiona una directory alla ricerca di file .log e stampa un riepilogo.

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

Eseguilo come python summarize.py /var/log e stamperà il nome e la dimensione in byte di ogni file .log in quella directory.

os vs pathlib — Quale usare?

Python 3.4 ha introdotto pathlib.Path, un'alternativa orientata agli oggetti a os.path. Entrambi gli approcci sono corretti; la scelta è principalmente una preferenza stilistica.

OperazioneStile osStile pathlib
Unire percorsios.path.join(a, b)Path(a) / b
Ottenere il nome del fileos.path.basename(p)Path(p).name
Ottenere l'estensioneos.path.splitext(p)[1]Path(p).suffix
Verificare l'esistenzaos.path.exists(p)Path(p).exists()
Leggere un file di testoopen(p).read()Path(p).read_text()
Elencare una directoryos.listdir(p)list(Path(p).iterdir())

pathlib tende a produrre codice più leggibile per gli script con molti percorsi; os.path è familiare e supportato ovunque giri Python 3. Il modulo sys non ha un equivalente in pathlib — si usa sempre import sys.

Esercitati

Pratica
Which function returns the current working directory in Python?
Which function returns the current working directory in Python?
Pratica
What does sys.argv[0] contain when you run a Python script from the command line?
What does sys.argv[0] contain when you run a Python script from the command line?

Capitoli correlati

Was this page helpful?