Python subprocess: esecuzione di comandi e programmi esterni
Il modulo Python subprocess
ti consente di controllare, eseguire e valutare programmi esterni all’interno del codice. Le due funzioni più importanti di questo strumento sono run()
e Popen()
.
Che cos’è Python subprocess
?
Il modulo Python subprocess
fa parte dell’inventario di questo linguaggio di programmazione a partire dalla versione 2.4. È uno strumento molto completo e potente che puoi utilizzare per eseguire altri programmi o comandi all’interno del tuo codice. Non soltanto ti permette di aprire i programmi, ma anche di controllare e gestire il flusso di dati. Il modulo subprocess
di Python offre numerosi metodi e funzioni: in questo articolo esamineremo i più importanti, spiegandoli per mezzo di alcuni esempi pratici.
- Massima sicurezza dei tuoi dati
- Strumenti di collaborazione per lavorare in team
- Aggiornamenti automatici
Il funzionamento di subprocess
con run()
Per prima cosa è utile dare un’occhiata alla struttura e alle funzionalità di base del modulo subprocess
di Python. Questo modulo è utilizzato per eseguire sottoprocessi. Python funziona secondo la gerarchia genitore-figlio (parent-child) con una parte sovraordinata (processo genitore) che genera un processo subordinato. La funzione utilizzata più spesso all’interno del modulo è run()
. Essa consente di avviare un processo tramite Python e di dare inizio ai passaggi successivi solo dopo aver completato tale processo.
Esempio di funzionamento di Python subprocess
con run()
Utilizziamo ora questa funzione per il nostro primo semplice esempio, che ci permette di illustrare il funzionamento di subprocess
in Python. A tal fine, importiamo prima i moduli subprocess
e sys
, quindi eseguiamo una semplice richiesta. Il relativo codice si presenta così:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('ciao')"])
pythonL’output è quindi il seguente:
ciao
pythonsubprocess.run
: questa è la funzione vera e propria. Essa riceve un elenco di stringhe contenenti il comando da eseguire. Successivamente,run()
esegue un nuovo programma Python.sys.executable
: consys.executable
si indica il percorso assoluto che porta al file Python utilizzato in origine per richiamare il programma. Tale percorso può essere ad esempio simile a questo:/local/utente/bin/esempio
.-c
:-c
è un’opzione da riga di comando che comunica la stringa specificata per l’esecuzione. Nel nostro esempio si tratta di un programma che emette la parola “ciao”.
Esecuzione di Python subprocess
con uno script
Per sperimentare l’uso del modulo per uno script personalizzato, puoi provare il seguente esempio. A tal fine, crea prima un semplice script in formato .py e salvalo come “esempioscript.py”:
print("Oggi è una bella giornata")
pythonOra utilizza il codice seguente per eseguire questo file con subprocess
in Python:
import subprocess
result = subprocess.run(["python", "esempioscript.py"], capture_output=True, text=True)
print(result.stdout)
pythonIl risultato che otteniamo si presenta così:
Oggi è una bella giornata
pythonApertura di programmi esterni
In generale, l’uso di subprocess
in Python e della funzione run()
permette di aprire qualsiasi programma. L’unico requisito è che tu conosca il nome esatto o il percorso in cui questo programma si trova sul tuo sistema. Ad esempio, nel codice seguente apriamo il Blocco note (Notepad):
import subprocess
subprocess.run(["notepad"])
pythonCompletedProcess
e acquisizione di output esterni
Dopo questi semplici esempi, passiamo ora a esaminare l’acquisizione di un output esterno. A tal fine eseguiamo un programma esterno con subprocess
di Python come nell’esempio precedente, ma chiediamo al sistema di restituire un cosiddetto oggetto CompletedProcess
. Le modifiche necessarie sono già presenti in un esempio precedente, ma ora passiamo ad analizzarle più in dettaglio. Il punto di partenza è ancora una volta il nostro primo codice. Ora lo modifichiamo come segue:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('ciao')"], capture_output=True, text=True)
print("L'output standard è:", result.stdout)
print("Questo è l'errore standard:", result.stderr)
pythonAnche questa volta chiediamo al sistema di emettere la stringa di caratteri “ciao”. Questa operazione avviene in un processo subordinato. Tuttavia sono presenti i due nuovi argomenti chiave capture_output=True
e text=True
, che assegniamo a run()
. Se l’istruzione viene eseguita e non restituisce errori, ottieni un oggetto CompletedProcess
con un collegamento a result
. L’oggetto contiene informazioni sul codice di uscita del programma che desideri eseguire e le trasmette a result.stdout
e result.stderr
. stdout
contraddistingue l’output standard, mentre stderr
indica i possibili errori standard. Inoltre, text=True
serve a stampare l’output sotto forma di stringa. Poiché non è previsto alcun errore standard, il risultato che otteniamo è il seguente:
L'output standard è: ciao
Questo è l'errore standard:
pythonPer illustrare il funzionamento, nel prossimo esempio facciamo in modo che questa volta stderr
non resti vuoto. Il codice da utilizzare è il seguente:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "raise ValueError('errore')"], capture_output=True, text=True)
print("L'output standard è:", result.stdout)
print("Questo è l'errore standard:", result.stderr)
pythonMentre questa volta l’output standard rimane vuoto, è ora presente un output per stderr
:
L'output standard è:
Questo è l'errore standard: Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: errore
pythonEsecuzione di una funzione
Il modulo subprocess
in Python ti permette anche di integrare un comando direttamente nel codice. In questo caso il codice potrebbe presentarsi come in questo esempio:
import subprocess
result = subprocess.run(["C:/Utenti/nome/anaconda3/python", "-c", "print('Questo output è stato preso direttamente da una funzione')"], capture_output=True, text=True, shell=True)
print("L'output standard è:", result.stdout)
pythonL’output che otteniamo si presenta così:
L'output standard è: Questo output è stato preso direttamente da una funzione
pythonInterruzione o conclusione di processi
Un’altra applicazione molto utile di subprocess
in Python è tramite l’interazione tra run()
e l’argomento timeout
. In questo modo puoi interrompere un programma esterno se la sua esecuzione impiega troppo tempo. A tal fine si utilizza la funzione time.sleep
. Il relativo codice è l seguente:
import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "import time; time.sleep(3)"], timeout=1)
pythonIl processo subordinato utilizza time.sleep
per una sospensione di tre secondi. Tuttavia, poiché hai indicato al sistema di far partire un timeout dopo un secondo con timeout=1
, il risultato è un’eccezione TimeoutExpired
.
Python subprocess
con Popen()
Sebbene run() sia la funzione di Python subprocess
usata più spesso, esistono anche altre importanti classi che possono esserti molto utili. Tra queste vi è anche Popen()
. Questa classe è in un certo senso la struttura alla base di subprocess
in Python ed è un po’ più complessa da usare rispetto a run()
. Tuttavia, Popen()
ti offre un maggiore controllo sull’esecuzione e può interagire con input e output. La classe deve il suo nome a un comando UNIX e sta per “pipe open”.
Quasi tutti gli argomenti che puoi utilizzare con run()
sono consentiti anche con Popen()
. A differenza di run()
, questa funzione non attende il completamento di un processo, ma ne avvia un secondo in parallelo. È possibile illustrare il funzionamento con un semplice esempio:
import subprocess
from time import sleep
def poll_and_read(process):
print(f"Questo è l'output dopo poll(): {process.poll()}")
print(f"Questo è l'output standard: {process.stdout.read().decode('utf-8')}")
process = subprocess.Popen(["python", "timer.py", "3"], stdout=subprocess.PIPE)
poll_and_read(process)
sleep(2)
poll_and_read(process)
sleep(2)
poll_and_read(process)
process.wait()
print(f"Codice di uscita del processo: {process.returncode}")
pythonQui utilizziamo il metodo .poll()
per verificare se il processo è ancora in esecuzione o se è già stato completato. Finché è ancora in esecuzione, viene emesso il valore “none”. Successivamente, il metodo restituisce il codice di uscita. Con .read()
devono essere letti tutti i byte che si trovano attualmente in .stdout
. Eseguendo il codice, si ottiene prima il valore “None”, quindi il valore attualmente contenuto in stdout
. La procedura continua fino al completamento del processo. Infine, poll()
acquisisce il valore “0”.
Deployment di app e siti web direttamente con GitHub: con Deploy Now di IONOS puoi trarre vantaggio da una configurazione più rapida, flussi di lavoro ottimizzati ed eccellente scalabilità. Trova il piano più adatto alle tue esigenze.