Il modulo Python subprocess ti consente di con­trol­la­re, eseguire e valutare programmi esterni all’interno del codice. Le due funzioni più im­por­tan­ti di questo strumento sono run() e Popen().

Che cos’è Python subprocess?

Il modulo Python subprocess fa parte dell’in­ven­ta­rio di questo lin­guag­gio di pro­gram­ma­zio­ne a partire dalla versione 2.4. È uno strumento molto completo e potente che puoi uti­liz­za­re per eseguire altri programmi o comandi all’interno del tuo codice. Non soltanto ti permette di aprire i programmi, ma anche di con­trol­la­re e gestire il flusso di dati. Il modulo subprocess di Python offre numerosi metodi e funzioni: in questo articolo esa­mi­ne­re­mo i più im­por­tan­ti, spie­gan­do­li 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 col­la­bo­ra­zio­ne per lavorare in team
  • Ag­gior­na­men­ti au­to­ma­ti­ci

Il fun­zio­na­men­to di subprocess con run()

Per prima cosa è utile dare un’occhiata alla struttura e alle fun­zio­na­li­tà di base del modulo subprocess di Python. Questo modulo è uti­liz­za­to per eseguire sot­to­pro­ces­si. Python funziona secondo la gerarchia genitore-figlio (parent-child) con una parte so­vraor­di­na­ta (processo genitore) che genera un processo su­bor­di­na­to. La funzione uti­liz­za­ta più spesso all’interno del modulo è run(). Essa consente di avviare un processo tramite Python e di dare inizio ai passaggi suc­ces­si­vi solo dopo aver com­ple­ta­to tale processo.

Esempio di fun­zio­na­men­to di Python subprocess con run()

Uti­liz­zia­mo ora questa funzione per il nostro primo semplice esempio, che ci permette di il­lu­stra­re il fun­zio­na­men­to di subprocess in Python. A tal fine, im­por­tia­mo 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 con­te­nen­ti il comando da eseguire. Suc­ces­si­va­men­te, run() esegue un nuovo programma Python.
  • sys.executable: con sys.executable si indica il percorso assoluto che porta al file Python uti­liz­za­to in origine per ri­chia­ma­re 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 spe­ci­fi­ca­ta per l’ese­cu­zio­ne. Nel nostro esempio si tratta di un programma che emette la parola “ciao”.

Ese­cu­zio­ne di Python subprocess con uno script

Per spe­ri­men­ta­re l’uso del modulo per uno script per­so­na­liz­za­to, puoi provare il seguente esempio. A tal fine, crea prima un semplice script in formato .py e salvalo come “esem­pio­script.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 ac­qui­si­zio­ne di output esterni

Dopo questi semplici esempi, passiamo ora a esaminare l’ac­qui­si­zio­ne di un output esterno. A tal fine eseguiamo un programma esterno con subprocess di Python come nell’esempio pre­ce­den­te, ma chiediamo al sistema di re­sti­tui­re un co­sid­det­to oggetto CompletedProcess. Le modifiche ne­ces­sa­rie sono già presenti in un esempio pre­ce­den­te, ma ora passiamo ad ana­liz­zar­le più in dettaglio. Il punto di partenza è ancora una volta il nostro primo codice. Ora lo mo­di­fi­chia­mo 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 ope­ra­zio­ne avviene in un processo su­bor­di­na­to. Tuttavia sono presenti i due nuovi argomenti chiave capture_output=True e text=True, che as­se­gnia­mo a run(). Se l’istru­zio­ne viene eseguita e non re­sti­tui­sce errori, ottieni un oggetto CompletedProcess con un col­le­ga­men­to a result. L’oggetto contiene in­for­ma­zio­ni sul codice di uscita del programma che desideri eseguire e le trasmette a result.stdout e result.stderr. stdout con­trad­di­stin­gue 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 il­lu­stra­re il fun­zio­na­men­to, nel prossimo esempio facciamo in modo che questa volta stderr non resti vuoto. Il codice da uti­liz­za­re è 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

Ese­cu­zio­ne di una funzione

Il modulo subprocess in Python ti permette anche di integrare un comando di­ret­ta­men­te nel codice. In questo caso il codice potrebbe pre­sen­tar­si 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

In­ter­ru­zio­ne o con­clu­sio­ne di processi

Un’altra ap­pli­ca­zio­ne molto utile di subprocess in Python è tramite l’in­te­ra­zio­ne tra run() e l’argomento timeout. In questo modo puoi in­ter­rom­pe­re un programma esterno se la sua ese­cu­zio­ne 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 su­bor­di­na­to utilizza time.sleep per una so­spen­sio­ne 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 im­por­tan­ti 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’ese­cu­zio­ne e può in­te­ra­gi­re 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 uti­liz­za­re con run() sono con­sen­ti­ti anche con Popen() . A dif­fe­ren­za di run(), questa funzione non attende il com­ple­ta­men­to di un processo, ma ne avvia un secondo in parallelo. È possibile il­lu­stra­re il fun­zio­na­men­to 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 uti­liz­zia­mo il metodo .poll() per ve­ri­fi­ca­re se il processo è ancora in ese­cu­zio­ne o se è già stato com­ple­ta­to. Finché è ancora in ese­cu­zio­ne, viene emesso il valore “none”. Suc­ces­si­va­men­te, il metodo re­sti­tui­sce il codice di uscita. Con .read() devono essere letti tutti i byte che si trovano at­tual­men­te in .stdout. Eseguendo il codice, si ottiene prima il valore “None”, quindi il valore at­tual­men­te contenuto in stdout. La procedura continua fino al com­ple­ta­men­to del processo. Infine, poll() ac­qui­si­sce il valore “0”.

Consiglio

De­ploy­ment di app e siti web di­ret­ta­men­te con GitHub: con Deploy Now di IONOS puoi trarre vantaggio da una con­fi­gu­ra­zio­ne più rapida, flussi di lavoro ot­ti­miz­za­ti ed ec­cel­len­te sca­la­bi­li­tà. Trova il piano più adatto alle tue esigenze.

Vai al menu prin­ci­pa­le