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.

Managed Nextcloud di IONOS Cloud
Lavora con il tuo team sul cloud
  • 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')"])
python

L’output è quindi il seguente:

ciao
python
  • subprocess.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: con sys.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")
python

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

Il risultato che otteniamo si presenta così:

Oggi è una bella giornata
python

Apertura 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"])
python

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

Anche 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:
python

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

Mentre 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
python

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

L’output che otteniamo si presenta così:

L'output standard è: Questo output è stato preso direttamente da una funzione
python

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

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

Qui 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”.

Consiglio

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.

Hai trovato questo articolo utile?
Vai al menu principale